rust 将一个vector中的所有内容移动到一个新的vector中

rggaifut  于 2023-10-20  发布在  其他
关注(0)|答案(4)|浏览(143)

要使用旧vector的内容创建新vector(我想清空旧vector),我将使用:用途:

foo.bar = my_vector.drain(0..).collect();

这是惯用的Rust吗?
drain()是否被优化掉了,而原始向量的内存只是给了新向量?
或者每个元素都被一个接一个地复制到一个新的堆分配中?

xa9qqrwz

xa9qqrwz1#

我会做

foo.bar = std::mem::take(&mut my_vector);

这是一个更一般的解决方案。
std::mem::take()改变其参数,以便 * 窃取 * 其内容并使其保持默认状态。窃取的内容用于创建相同类型的新值。
实际的 * 窃取 * 操作是结构本身的简单字节交换(一些指针/整数用于VecString,任何其他容器...)。存储的元素,可能是堆分配的,留在原地,因此这个操作最终是非常便宜的(复制然后清除很少的字节,即sizeof结构)。

flvlnr44

flvlnr442#

将所有元素从一个Vec移动到另一个take的最便宜的方法是take它们:

foo.bar = std::mem::take(&mut my_vector);

这将给予分配和所有元素的所有权给foo.bar,并使my_vector处于默认状态(空,没有分配空间)。
你可以使用.drain() + .collect()来移动元素,同时保留my_vector的分配,但是你可以通过使用上面的方法来避免复制成本,然后再简单地将空间放回.reserve()
如果foo.bar也分配了元素或空间,那么最好是swap它们(交换它们的元素和分配),然后清除my_vector,如果你想让它为空:

std::mem::swap(&mut foo.bar, &mut my_vector);
my_vector.clear();

这可以避免以后将元素放入my_vector时的分配。

ctzwtxfj

ctzwtxfj3#

我不认为编译器看到了这种优化,我也不完全确定它是否有效。你可以看到on the compiler explorer,你的代码确实发出了分配,后面跟着一个memmove

//…
355:         mov     edi, 396
356:         mov     esi, 4
357:         call    qword ptr [rip + __rust_alloc@GOTPCREL]
//…
442:         call    qword ptr [rip + memmove@GOTPCREL]
//…

为了drain一个完整的向量,我会使用drain(..),越少的显式数字越好,但更符合你的意图的可能是

foo.bar = std::mem::take(&mut my_vector);

let cap = my_vector.capacity();
foo.bar = std::mem::replace(&mut my_vector, Vec::with_capacity(cap));
r7xajy2e

r7xajy2e4#

如果你不想重新分配,请使用std::mem::take(),因为@ fx-fh已经回答过了。
我只是想添加一些示例,说明这对生成的机器代码有什么影响。
下面是你的代码编译成的内容:

pub fn move_drain(my_vector: &mut Vec<u8>) -> Vec<u8>{
    my_vector.drain(0..).collect()
}
core::ptr::drop_in_place<alloc::vec::Vec<u8>>:
        test    rsi, rsi
        je      .LBB0_1
        mov     edx, 1
        jmp     qword ptr [rip + __rust_dealloc@GOTPCREL]
.LBB0_1:
        ret

core::ptr::drop_in_place<alloc::vec::drain::Drain<u8>>:
        push    r15
        push    r14
        push    rbx
        lea     rax, [rip + .Lanon.716d6a888caeb235278dc75f1465c66b.0]
        mov     rcx, qword ptr [rdi + 8]
        mov     rbx, qword ptr [rdi + 32]
        cmp     rcx, qword ptr [rdi]
        mov     qword ptr [rdi], rax
        mov     qword ptr [rdi + 8], rax
        test    rbx, rbx
        je      .LBB1_4
        mov     rax, qword ptr [rdi + 16]
        mov     rsi, qword ptr [rdi + 24]
        lea     r14, [rax + 16]
        mov     r15, qword ptr [rax + 16]
        cmp     rsi, r15
        je      .LBB1_3
        mov     rdi, qword ptr [rax]
        add     rsi, rdi
        add     rdi, r15
        mov     rdx, rbx
        call    qword ptr [rip + memmove@GOTPCREL]
.LBB1_3:
        add     r15, rbx
        mov     qword ptr [r14], r15
.LBB1_4:
        pop     rbx
        pop     r14
        pop     r15
        ret

alloc::raw_vec::finish_grow:
        push    r15
        push    r14
        push    rbx
        mov     rbx, rdx
        mov     r14, rdi
        test    rsi, rsi
        je      .LBB2_6
        mov     r15, rsi
        cmp     qword ptr [rcx + 8], 0
        je      .LBB2_7
        mov     rsi, qword ptr [rcx + 16]
        test    rsi, rsi
        je      .LBB2_7
        mov     rdi, qword ptr [rcx]
        mov     rdx, r15
        mov     rcx, rbx
        call    qword ptr [rip + __rust_realloc@GOTPCREL]
        test    rax, rax
        jne     .LBB2_11
.LBB2_4:
        mov     qword ptr [r14 + 8], r15
        jmp     .LBB2_5
.LBB2_7:
        test    rbx, rbx
        je      .LBB2_8
        mov     rax, qword ptr [rip + __rust_no_alloc_shim_is_unstable@GOTPCREL]
        movzx   eax, byte ptr [rax]
        mov     rdi, rbx
        mov     rsi, r15
        call    qword ptr [rip + __rust_alloc@GOTPCREL]
        test    rax, rax
        je      .LBB2_4
.LBB2_11:
        mov     qword ptr [r14 + 8], rax
        xor     eax, eax
        jmp     .LBB2_12
.LBB2_6:
        mov     qword ptr [r14 + 8], 0
.LBB2_5:
        mov     eax, 1
.LBB2_12:
        mov     qword ptr [r14 + 16], rbx
        mov     qword ptr [r14], rax
        pop     rbx
        pop     r14
        pop     r15
        ret
.LBB2_8:
        mov     rax, r15
        test    rax, rax
        jne     .LBB2_11
        jmp     .LBB2_4

alloc::raw_vec::RawVec<T,A>::reserve::do_reserve_and_handle:
        push    r14
        push    rbx
        sub     rsp, 56
        add     rsi, rdx
        jb      .LBB3_10
        mov     rbx, rdi
        mov     rax, qword ptr [rdi + 8]
        lea     rcx, [rax + rax]
        cmp     rcx, rsi
        cmova   rsi, rcx
        cmp     rsi, 9
        mov     r14d, 8
        cmovae  r14, rsi
        mov     rsi, r14
        not     rsi
        shr     rsi, 63
        test    rax, rax
        je      .LBB3_2
        mov     rcx, qword ptr [rbx]
        mov     qword ptr [rsp + 8], rcx
        mov     qword ptr [rsp + 16], 1
        mov     qword ptr [rsp + 24], rax
        jmp     .LBB3_4
.LBB3_2:
        mov     qword ptr [rsp + 16], 0
.LBB3_4:
        lea     rdi, [rsp + 32]
        lea     rcx, [rsp + 8]
        mov     rdx, r14
        call    alloc::raw_vec::finish_grow
        cmp     qword ptr [rsp + 32], 0
        mov     rdi, qword ptr [rsp + 40]
        je      .LBB3_5
        movabs  rax, -9223372036854775807
        cmp     rdi, rax
        jne     .LBB3_8
        add     rsp, 56
        pop     rbx
        pop     r14
        ret
.LBB3_5:
        mov     qword ptr [rbx], rdi
        mov     qword ptr [rbx + 8], r14
        add     rsp, 56
        pop     rbx
        pop     r14
        ret
.LBB3_8:
        test    rdi, rdi
        jne     .LBB3_9
.LBB3_10:
        call    qword ptr [rip + alloc::raw_vec::capacity_overflow@GOTPCREL]
        ud2
.LBB3_9:
        mov     rsi, qword ptr [rsp + 48]
        call    qword ptr [rip + alloc::alloc::handle_alloc_error@GOTPCREL]
        ud2

example::move_drain:
        push    r15
        push    r14
        push    r13
        push    r12
        push    rbx
        sub     rsp, 112
        mov     rbx, rdi
        mov     rax, qword ptr [rsi]
        mov     r14, qword ptr [rsi + 16]
        mov     qword ptr [rsi + 16], 0
        mov     qword ptr [rsp + 72], rax
        add     rax, r14
        mov     qword ptr [rsp + 80], rax
        mov     qword ptr [rsp + 88], rsi
        mov     qword ptr [rsp + 96], r14
        mov     qword ptr [rsp + 104], 0
        test    r14, r14
        je      .LBB4_1
        setns   al
        js      .LBB4_5
        movzx   r15d, al
        mov     rax, qword ptr [rip + __rust_no_alloc_shim_is_unstable@GOTPCREL]
        movzx   eax, byte ptr [rax]
        mov     rdi, r14
        mov     rsi, r15
        call    qword ptr [rip + __rust_alloc@GOTPCREL]
        test    rax, rax
        jne     .LBB4_2
        mov     rdi, r15
        mov     rsi, r14
        call    qword ptr [rip + alloc::alloc::handle_alloc_error@GOTPCREL]
        jmp     .LBB4_6
.LBB4_1:
        mov     eax, 1
.LBB4_2:
        mov     qword ptr [rsp + 8], rax
        mov     qword ptr [rsp + 16], r14
        mov     qword ptr [rsp + 24], 0
        vmovups ymm0, ymmword ptr [rsp + 72]
        vmovups ymmword ptr [rsp + 32], ymm0
        mov     rcx, qword ptr [rsp + 104]
        mov     qword ptr [rsp + 64], rcx
        mov     r15, qword ptr [rsp + 32]
        mov     r12, qword ptr [rsp + 40]
        mov     rdx, r12
        sub     rdx, r15
        cmp     r14, rdx
        jae     .LBB4_3
        lea     rdi, [rsp + 8]
        xor     esi, esi
        vzeroupper
        call    alloc::raw_vec::RawVec<T,A>::reserve::do_reserve_and_handle
        mov     rax, qword ptr [rsp + 8]
        mov     rcx, qword ptr [rsp + 24]
        jmp     .LBB4_11
.LBB4_3:
        xor     ecx, ecx
.LBB4_11:
        mov     r13, qword ptr [rsp + 48]
        mov     rsi, qword ptr [rsp + 56]
        mov     r14, qword ptr [rsp + 64]
        cmp     r15, r12
        je      .LBB4_14
.LBB4_12:
        movzx   edx, byte ptr [r15]
        inc     r15
        mov     byte ptr [rax + rcx], dl
        inc     rcx
        cmp     r15, r12
        jne     .LBB4_12
.LBB4_14:
        mov     qword ptr [rsp + 24], rcx
        test    r14, r14
        je      .LBB4_18
        mov     r15, qword ptr [r13 + 16]
        cmp     rsi, r15
        je      .LBB4_17
        mov     rdi, qword ptr [r13]
        add     rsi, rdi
        add     rdi, r15
        mov     rdx, r14
        vzeroupper
        call    qword ptr [rip + memmove@GOTPCREL]
.LBB4_17:
        add     r15, r14
        mov     qword ptr [r13 + 16], r15
.LBB4_18:
        mov     rax, qword ptr [rsp + 24]
        mov     qword ptr [rbx + 16], rax
        vmovups xmm0, xmmword ptr [rsp + 8]
        vmovups xmmword ptr [rbx], xmm0
        mov     rax, rbx
        add     rsp, 112
        pop     rbx
        pop     r12
        pop     r13
        pop     r14
        pop     r15
        vzeroupper
        ret
.LBB4_5:
        call    qword ptr [rip + alloc::raw_vec::capacity_overflow@GOTPCREL]
.LBB4_6:
        ud2
        mov     rbx, rax
        lea     rdi, [rsp + 32]
        call    core::ptr::drop_in_place<alloc::vec::drain::Drain<u8>>
        mov     rdi, qword ptr [rsp + 8]
        mov     rsi, qword ptr [rsp + 16]
        call    core::ptr::drop_in_place<alloc::vec::Vec<u8>>
        mov     rdi, rbx
        call    _Unwind_Resume@PLT
        ud2
        mov     rbx, rax
        lea     rdi, [rsp + 72]
        call    core::ptr::drop_in_place<alloc::vec::drain::Drain<u8>>
        mov     rdi, rbx
        call    _Unwind_Resume@PLT
        ud2

.Lanon.716d6a888caeb235278dc75f1465c66b.0:

DW.ref.rust_eh_personality:
        .quad   rust_eh_personality

与此相反,这里使用std::mem::take

pub fn move_take(my_vector: &mut Vec<u8>) -> Vec<u8>{
    std::mem::take(my_vector)
}
example::move_take:
        mov     rax, rdi
        mov     rcx, qword ptr [rsi + 16]
        mov     qword ptr [rdi + 16], rcx
        vmovups xmm0, xmmword ptr [rsi]
        vmovups xmmword ptr [rdi], xmm0
        mov     qword ptr [rsi], 1
        vxorps  xmm0, xmm0, xmm0
        vmovups xmmword ptr [rsi + 8], xmm0
        ret

相关问题