Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/144.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 我们需要移动和复制任务吗_C++_C++11_Move Semantics_Assignment Operator - Fatal编程技术网

C++ 我们需要移动和复制任务吗

C++ 我们需要移动和复制任务吗,c++,c++11,move-semantics,assignment-operator,C++,C++11,Move Semantics,Assignment Operator,对于类a,我们可以使用 A& operator=( A other ) { /* ... */ } 而不是 A& operator=( const A& other ) { /* ... */ } A& operator=( const A&& other ) { /* ... */ } 在不降低性能或其他负面影响的情况下?实际上,您可以使用实现复制和交换 A& operator=( A other ) { swap(other, *

对于类
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
,移动应该是轻量级的,便宜的,它不是必需的,但应该是轻量级的。因此,移动构造函数/赋值应该是
noexcept
。如果没有
noexcept
move构造函数/赋值运算符,当容器增长时无法调用,容器将返回到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;
}
没有恶化的表现或其他负面影响

它取决于
A
的数据成员和基类,甚至可以取决于A的基和成员的基和成员

下面是一段视频的链接,该视频演示了如果
a
有一个
vector
作为数据成员,那么复制/交换习惯用法对复制分配操作符的平均性能影响为70%。这与默认指定特殊成员的方法相比要容易得多

A类
{
std::向量v_;
公众:
// ...
};
您可以期望
string
数据成员与
vector
数据成员具有相同的影响

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

  • “移动”上下文的性能可能会受到轻微影响

    如果类
    A
    是可移动的,则在移动上下文中,按值复制和交换实现将以两个操作的顺序实现移动:

  • 使用
    A
    的移动构造函数将右侧(RHS)值移动到参数
    other
  • 将数据从
    其他
    移动到
    *此
    (或用
    *此
    交换
    其他
  • 第二个实现(使用专用移动分配)可以在一个操作中完成相同的操作:它将直接使用
    *this
    移动(或交换)右侧值

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

  • “复制”上下文的性能可能会受到轻微或严重的影响

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

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


在大多数情况下,您可以允许编译器为您生成复制和移动赋值运算符。在许多情况下,这样的复制赋值运算符将是次优的,因为当
可能已经具有可重用的容量时,您正在对
其他
进行无条件复制。这个答案是错误的。首先,此实现不会阻止我们将复制分配操作符声明为
noexcept
。这里唯一可以抛出的是参数的复制构造函数。但如果发生这种情况,它总是发生在调用方的上下文中(!)。这意味着,如果
swap
noexcept
(应该是这样),那么您也可以自由地将这个“按值传递”赋值声明为
noexcept
。为了正常工作而不损失性能,类必须正确有效地定义复制构造函数和移动构造函数。后者显然可以是
noexcept
,这意味着在移动上下文中,上述赋值运算符的“按值传递”实现将完全没有异常。@Chris Drew:很好。这确实是一个很好的例子,说明了“按值传递”的习惯用法不起作用。在移动赋值运算符中省略自赋值检查是有争议的,
class A
{
    std::vector<int> v_;
public:
    // ...
};