我们需要移动和复制作业吗

Do we need move and copy assignment

对于class A,我们可以使用

A& operator=( A other ) { /* ... */ }

而不是

A& operator=( const A&  other ) { /* ... */ }
A& operator=( const A&& other ) { /* ... */ }

不会降低性能或产生其他负面影响?

实际上,您可以使用

实现复制和交换
A& operator=( A other ) { swap(other, *this); return *this; }

对于复制和移动赋值,但自赋值运算符的无条件复制会降低性能。

除此之外,上面的功能不能标注noexcept move应该是轻量级的,廉价的,不是必需的,但它应该是轻量级的。因此,移动 constructor/assignment 应该是 noexcept。没有noexcept move constructor/assignment operator, move_if_noexcept 容器增长时无法调用,容器会回去copy.

因此,推荐的方式是:

A& operator=( const A&  other ) {
    if (std::addressof(other) != this) {
         A(other).swap(*this); // Copy constructor may throw
    }
    return *this;
}
A& operator=( A&& other ) noexcept { // note no const here
    // we don't check self assignment because
    // an object binds to an rvalue reference it is one of two things:
    //    - A temporary.
    //    - An object the caller wants you to believe is a temporary.
    swap(other); 
    return *this;
}

without worsening performance or other negative effects?

依赖A的数据成员和基类,甚至可以依赖A的基和成员的基和成员

这是视频的一部分 link,它演示了如果 A 有一个 vector 作为数据成员,那么 copy/swap 习语可以花费复制赋值运算符 70% 的性能命中率 平均 。这与默认分配特殊成员的更简单方法相比。

http://www.youtube.com/watch?v=vLinb2fgkHk&t=35m30s

class A
{
    std::vector<int> v_;
public:
    // ...
};

您可以预期 string 个数据成员具有与 vector 个数据成员相同的影响。

如果您不确定 A,并且性能对您很重要,请尝试两种方式并进行衡量。这正是视频中演示的内容。

  • "move" 上下文的性能可能会受到轻微影响。

    如果您的 class A 是可移动的,那么在移动上下文中,按值传递复制和交换实现会将移动实现为两个操作的序列:

    1. 使用 A 的移动构造函数将右侧 (RHS) 值移动到参数 other
    2. 将数据从 other 移动到 *this(或将 other 替换为 *this)。

    第二个实现(使用专门的移动赋值)可以在一个操作中完成同样的事情:它会直接移动(或交换)右边的值 *this

    因此,复制和交换变体可能会涉及一次额外移动的开销。

  • "copy" 上下文的性能可能会受到轻微或严重的影响。

    如果您的左侧 (LHS) 有一些可复制的内部资源(如内存块)可以容纳相应的 RHS 值而无需重新分配,那么复制分配的专用实现只需要从复制数据RHS 资源到 LHS 资源。不需要内存分配。

    在复制和交换变体中,副本是无条件创建的,并且必须无条件地分配和释放上述内部资源。这会对性能产生重大负面影响。