Memory 试图将一个Vec的内容复制到另一个Vec中,如何使用copy_from_slice()?

Memory 试图将一个Vec的内容复制到另一个Vec中,如何使用copy_from_slice()?,memory,vector,rust,Memory,Vector,Rust,我试图将Vec的内容复制到现有Vec中,替换目标Vec的内容 以下是我想要的: 不需要分配新内存(除非目标Vec太短),因为目标Vec已分配 它不应该使用迭代器,因为memcopy应该足以完成这项工作 不应更改源Vec 理想情况下,它应该使用安全的方法 以下是我尝试过的: vec.clone() vec.clear();vec.extend():复制到位,但似乎在每个元素上都使用了迭代器,这是不需要的,我只需要一个memcopy vec.copy\u from\u slice():是我正在

我试图
Vec
的内容复制到现有
Vec
中,替换目标
Vec
的内容

以下是我想要的:

  • 不需要分配新内存(除非目标
    Vec
    太短),因为目标
    Vec
    已分配
  • 它不应该使用迭代器,因为memcopy应该足以完成这项工作
  • 不应更改源
    Vec
  • 理想情况下,它应该使用安全的方法
以下是我尝试过的:

  • vec.clone()
  • vec.clear();vec.extend():复制到位,但似乎在每个元素上都使用了迭代器,这是不需要的,我只需要一个memcopy
  • vec.copy\u from\u slice()
    :是我正在寻找的,但需要完全相同大小的缓冲区,由于某种原因,我似乎无法获得
什么不起作用 问题 使用
vec.copy\u from_slice()
似乎是将
vec
的内容就地memcopy到另一个的方法,无需不必要的内存分配,也无需使用迭代器

如何设置目标
Vec
的大小,以便
Vec.copy\u from\u slice()
不会死机?

您可以使用以下功能:

fn vec_copy(src: &Vec<i32>, dst: &mut Vec<i32>) {
    dst.resize(src.len(), 0);
    dst.copy_from_slice(src.as_slice());
}

fn main() {
    // Copy from a shorter Vec
    let mut container = vec![1, 2];
    let test1 = vec![3]; // shorter vec
    println!("{:p} = {:?}", &container[0], container); // output: 0x7f00bda20008 = [1, 2]
    vec_copy(&test1, &mut container); // panics inside function 
    println!("{:p} = {:?}", &container[0], container); // expected: 0x7f00bda20008 = [3]

    // Copy from a longer Vec
    container = vec![1, 2];    
    let test2 = vec![4, 5, 6]; // longer Vec
    println!("{:p} = {:?}", &container[0], container); // output: 0x7fef5b820018 = [1, 2]
    vec_copy(&test2, &mut container); // panics inside function
    println!("{:p} = {:?}", &container[0], container); // expected: 0x7fef5b820018 = [4, 5, 6]    
}

最后一个有不同的地址,可能是因为目的地的容量比源地小,所以它必须增长,这意味着重新分配。这可以通过打印出目的地的容量,并观察其从2->4增长来显示:

println!("{:p} = {:?} (capacity: {:?})", &container[0], container, container.capacity());
vec_copy(&test2, &mut container); // panics inside function
println!("{:p} = {:?} (capacity: {:?})", &container[0], container, container.capacity());
输出:

0x7f2e36020008 = [1, 2]
0x7f2e36020008 = [3]
0x7f2e36020028 = [1, 2]
0x7f2e3602a010 = [4, 5, 6]
0x7f16a1820008 = [1, 2]
0x7f16a1820008 = [3]
0x7f16a1820028 = [1, 2] (capacity: 2)
0x7f16a182a010 = [4, 5, 6] (capacity: 4)

您可以通过确保目标在创建时足够大来防止这种情况。

您需要:


container.as_ptr()
&container[0]
更明显,并且当向量为空时不会失败

另见:


它不应该使用迭代器,因为memcopy应该足以胜任这项工作-这假设迭代器排除memcpy,但事实并非如此。@Shepmaster是的,我有一个先入为主的想法,迭代器(因为名称)将在循环中独立复制每个元素,而不是执行一个大的memcpy。今天我学会了。谢谢!是的,当目的地因为realloc而变小时,地址是不同的,我不知道为什么我错过了那个。您的解决方案是有效的,我最终接受了@Shipmaster的答案,因为它不需要在realloc的情况下用伪值填充目的地(这里是
resize()
),并且它仍然在内部使用
copy\u from\u slice()
。当然,不用担心,我理解并同意。很乐意帮忙!谢谢你的各种提示!我担心
extend\u from\u slice()
会在循环中独立复制每个元素。我被以下状态弄糊涂了:“迭代切片,克隆每个元素,然后将其附加到这个Vec”。但它最终在内部调用了
copy\u from_slice()
,并执行了一个独特的memcpy,这正是我想要的。在复制之前,它会执行一个
reserve()
set_len()
,这就是为什么我们可以在之前使用
truncate()
。请注意,
vec.truncate(0)
可以缩写为
vec.clear()
0x7f16a1820008 = [1, 2]
0x7f16a1820008 = [3]
0x7f16a1820028 = [1, 2] (capacity: 2)
0x7f16a182a010 = [4, 5, 6] (capacity: 4)
fn vec_copy(src: &[i32], dst: &mut Vec<i32>) {
    // Optionally truncate to zero if there might be existing data
    // dst.clear();
    dst.extend_from_slice(src);
}
playground::vec_copy:
    pushq   %r15
    pushq   %r14
    pushq   %r12
    pushq   %rbx
    subq    $88, %rsp
    movq    %rdx, %rbx
    movq    %rsi, %r15
    movq    %rdi, %r14
    movq    8(%rbx), %rsi
    movq    16(%rbx), %r12
    movq    %rsi, %rax
    subq    %r12, %rax
    cmpq    %r15, %rax
    jae .LBB1_14
    addq    %r15, %r12
    jb  .LBB1_8
    leaq    (%rsi,%rsi), %rax
    cmpq    %rax, %r12
    cmovbq  %rax, %r12
    movl    $4, %ecx
    movq    %r12, %rax
    mulq    %rcx
    jo  .LBB1_8
    testq   %rsi, %rsi
    je  .LBB1_9
    shlq    $2, %rsi
    movq    (%rbx), %rdi
    movq    %rsp, %r9
    movl    $4, %edx
    movl    $4, %r8d
    movq    %rax, %rcx
    callq   __rust_realloc@PLT
    testq   %rax, %rax
    jne .LBB1_5
    movq    (%rsp), %rax
    jmp .LBB1_12

.LBB1_9:
    movq    %rsp, %rdx
    movl    $4, %esi
    movq    %rax, %rdi
    callq   __rust_alloc@PLT
    testq   %rax, %rax
    je  .LBB1_12

.LBB1_5:
    xorl    %ecx, %ecx
    movdqa  32(%rsp), %xmm0
    movdqa  %xmm0, 48(%rsp)
    testq   %rcx, %rcx
    je  .LBB1_13

.LBB1_6:
    movq    %rax, (%rsp)
    movaps  48(%rsp), %xmm0
    movups  %xmm0, 8(%rsp)
    leaq    64(%rsp), %rdi
    movq    %rsp, %rsi
    callq   <core::heap::CollectionAllocErr as core::convert::From<core::heap::AllocErr>>::from@PLT
    movdqa  64(%rsp), %xmm0
    movq    %xmm0, %rax
    cmpq    $3, %rax
    je  .LBB1_14
    cmpq    $2, %rax
    jne .LBB1_15

.LBB1_8:
    leaq    .Lbyte_str.5(%rip), %rdi
    callq   core::panicking::panic@PLT
    ud2

.LBB1_12:
    movups  8(%rsp), %xmm0
    movaps  %xmm0, 32(%rsp)
    movl    $1, %ecx
    movdqa  32(%rsp), %xmm0
    movdqa  %xmm0, 48(%rsp)
    testq   %rcx, %rcx
    jne .LBB1_6

.LBB1_13:
    movq    %rax, (%rbx)
    movq    %r12, 8(%rbx)

.LBB1_14:
    movq    16(%rbx), %rdi
    leaq    (%rdi,%r15), %rax
    movq    %rax, 16(%rbx)
    shlq    $2, %r15
    shlq    $2, %rdi
    addq    (%rbx), %rdi
    movq    %r14, %rsi
    movq    %r15, %rdx
    callq   memcpy@PLT
    addq    $88, %rsp
    popq    %rbx
    popq    %r12
    popq    %r14
    popq    %r15
    retq

.LBB1_15:
    movq    80(%rsp), %rax
    movdqa  %xmm0, (%rsp)
    movq    %rax, 16(%rsp)
    movq    %rsp, %rdi
    callq   <alloc::heap::Heap as core::heap::Alloc>::oom
    ud2
println!("{:p} = {:?}", &container[0], container);