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