当前位置:  开发笔记 > 编程语言 > 正文

返回+重置成员变量最有效的方法?

如何解决《返回+重置成员变量最有效的方法?》经验,为你挑选了4个好方法。

什么是GetDeleteObjects下面实施的最有效的方式?

class Foo {
public:
  std::vector GetDeleteObjects();
private:
  std::vector objects_;
}

std::vector Foo::GetDeleteObjects() {
  std::vector result = objects_;
  objects_.clear();
  return result;
}

目前,至少执行从objects_到result的副本.std::move例如,这可以更快地制作吗?



1> 101010..:

你可以交换向量:

std::vector
Foo::GetDeleteObjects() {
  std::vector result;
  result.swap(objects_);
  return result;
}



2> Dietmar Kühl..:

您可以将移动构造用于移动感知类型,例如std::vector:

std::vector
Foo::GetDeleteObjects() {
     std::vector result(std::move(objects_));
     objects_.clear(); // objects_ left in unspecified state after move
     return result;
}

移动构造期间的传输很可能已经重置了指针,并且clear()不会做任何事情.由于不能保证从物体移动到什么状态,遗憾的是,它是必要的clear().


@Walter:移动工作通常用于传输对象.原始状态确实取决于实现,它可能提供比标准C++库更强或更弱的保证.对于标准C++库类,从对象移动的是有效但未指定的声明,使得`clear()`成为必需.对于其他类型,可能需要使用不同的方法来恢复从对象移动到已知状态.移动"通常"用于临时对象是编译器隐式地知道它可以从这些移动,否则它需要是显式的.
对于Juan的好处,值得一提的是,重要的是编写明确表达意图的正确代码.在几乎所有情况下,优化器都会比您更有效地实现您的意图.例如,在我使用的所有实现中,`clear()`中的代码将被优化掉 - 但它必须保持正确以使代码正确.

3> Richard Hodg..:

其他三个答案是正确的,所以在回答这个问题方面我没有什么可以补充的,但由于OP对效率感兴趣,我用-O3编译了所有建议.

两个解决方案之间几乎没有任何内容,但std::exchange解决方案在我的编译器上生成更高效的代码更加突出,并且具有额外的优势,即它在惯用方面是完美的.

我认为结果很有趣:

给定:

std::vector Foo::GetDeleteObjects1() {
    std::vector tmp;
    tmp.swap(objects_);
    return tmp;
}

结果是:

__ZN3Foo17GetDeleteObjects1Ev:
    .cfi_startproc
    pushq   %rbp
Ltmp0:
    .cfi_def_cfa_offset 16
Ltmp1:
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
Ltmp2:
    .cfi_def_cfa_register %rbp
    movq    $0, 8(%rdi)          ; construct tmp's allocator
    movq    $0, (%rdi)           ;... shame this wasn't optimised away
    movups  (%rsi), %xmm0        ; swap
    movups  %xmm0, (%rdi)
    xorps   %xmm0, %xmm0         ;... but compiler has detected that
    movups  %xmm0, (%rsi)        ;... LHS of swap will always be empty
    movq    16(%rsi), %rax       ;... so redundant fetch of LHS is elided
    movq    %rax, 16(%rdi)
    movq    $0, 16(%rsi)         ;... same here
    movq    %rdi, %rax
    popq    %rbp
    retq

给定:

std::vector
Foo::GetDeleteObjects2() {
    std::vector tmp = std::move(objects_);
    objects_.clear();
    return tmp;
}

结果是:

__ZN3Foo17GetDeleteObjects2Ev:
    .cfi_startproc
    pushq   %rbp
Ltmp3:
    .cfi_def_cfa_offset 16
Ltmp4:
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
Ltmp5:
    .cfi_def_cfa_register %rbp
    movq    $0, 8(%rdi)         ; move-construct ... shame about these
    movq    $0, (%rdi)          ; ... redundant zero-writes
    movups  (%rsi), %xmm0       ; ... copy right to left ...
    movups  %xmm0, (%rdi)
    movq    16(%rsi), %rax
    movq    %rax, 16(%rdi)
    movq    $0, 16(%rsi)      ; zero out moved-from vector ...
    movq    $0, 8(%rsi)       ; ... happens to be identical to clear()
    movq    $0, (%rsi)        ; ... so clear() is optimised away
    movq    %rdi, %rax    
    popq    %rbp
    retq

最后,给出:

std::vector
Foo::GetDeleteObjects3() {
    return std::exchange(objects_, {});
}

结果非常愉快:

__ZN3Foo17GetDeleteObjects3Ev:
    .cfi_startproc
    pushq   %rbp
Ltmp6:
    .cfi_def_cfa_offset 16
Ltmp7:
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
Ltmp8:
    .cfi_def_cfa_register %rbp
    movq    $0, (%rdi)            ; move-construct the result
    movq    (%rsi), %rax
    movq    %rax, (%rdi)
    movups  8(%rsi), %xmm0
    movups  %xmm0, 8(%rdi)
    movq    $0, 16(%rsi)          ; zero out the source
    movq    $0, 8(%rsi)
    movq    $0, (%rsi)
    movq    %rdi, %rax
    popq    %rbp
    retq

结论:

std :: exchange方法既具有惯用性,又具有最佳的效率.



4> ecatmur..:

惯用表达式将是使用std::exchange(自C++ 14):

std::vector Foo::GetDeleteObjects() {
  return std::exchange(objects_, {});
}

请注意,这假定分配值初始化vector等同于调用clear; 除非您使用有状态分配器,否则就会出现这种情况propagate_on_container_move_assignment,在这种情况下,您需要显式重用分配器:

std::vector Foo::GetDeleteObjects() {
  return std::exchange(objects_, std::vector(objects_.get_allocator()));
}

推荐阅读
小色米虫_524
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有