更正问题
的方式来实现复制&此举是为@Raxvan指出:
T& operator=(const T& other){
*this = T(other);
return *this;
}
但没有std::move
作为T(other)
已经是一个右值和铛会散发出在这里使用std::move
时,警告关于悲观情绪。
摘要
当移动赋值运算符存在,复制&交换和复制&移动之间的差别取决于用户是否使用具有比移动分配更好的异常安全swap
方法。对于标准std::swap
,复制&交换和复制&移动之间的异常安全性是相同的。我相信在大多数情况下,swap
和移动分配将具有相同的异常安全性(但并非总是如此)。
实现复制&移动有一个风险,其中如果移动赋值操作符不存在或有错误的签名,拷贝赋值运算符将减少到无限递归。但是至少铛发出警告这一点,并通过传递-Werror=infinite-recursion
编译器这种担心可以去掉,这很坦率地说我是无法理解为什么这是不是默认的错误,但我离题。
动机
我已经做了一些测试和大量的头划伤和这里的是我发现:
如果你有一招赋值操作符的“正确”的方式做复制&交换不会因调用工作operator=(T)
是暧昧与operator=(T&&)
。正如@Raxvan指出的那样,您需要在复制赋值运算符的主体内部执行复制构造。这被认为是较差的,因为它妨碍编译器在用右值调用运算符时执行复制elision。然而,复制删除将应用的情况现在由移动分配来处理,因此该点是没有意义的。
我们来对比:
T& operator=(const T& other){
using std::swap;
swap(*this, T(other));
return *this;
}
到:
T& operator=(const T& other){
*this = T(other);
return *this;
}
如果用户没有使用自定义swap
,那么模板std::swap(a,b)
使用。基本上做到这一点:
template<typename T>
void swap(T& a, T& b){
T c(std::move(a));
a = std::move(b);
b = std::move(c);
}
这意味着复制&交换的异常安全性是一样的异常安全的举动建设较弱,移动分配。如果用户使用自定义交换,那么异常安全性当然是由交换功能决定的。
在复制&移动,异常安全的举动赋值运算符完全决定。
我相信,在性能看这里是一种毫无意义的编译器优化将可能使有在大多数情况下没有什么区别。但无论如何,无论如何,我会对它进行评论,副本和掉期执行副本构建,移动构建和两个移动分配,而复制&移动副本构建和只有一个移动任务。虽然我是那种希望编译器根据T.炮制出在大多数情况下,在同一台机器代码,当然
附录:我以前
class T {
public:
T() = default;
T(const std::string& n) : name(n) {}
T(const T& other) = default;
#if 0
// Normal Copy & Swap.
//
// Requires this to be Swappable and copy constructible.
//
// Strong exception safety if `std::is_nothrow_swappable_v<T> == true` or user provided
// swap has strong exception safety. Note that if `std::is_nothrow_move_assignable` and
// `std::is_nothrow_move_constructible` are both true, then `std::is_nothrow_swappable`
// is also true but it does not hold that if either of the above are true that T is not
// nothrow swappable as the user may have provided a specialized swap.
//
// Doesn't work in presence of a move assignment operator as T t1 = std::move(t2) becomes
// ambiguous.
T& operator=(T other) {
using std::swap;
swap(*this, other);
return *this;
}
#endif
#if 0
// Copy & Swap in presence of copy-assignment.
//
// Requries this to be Swappable and copy constructible.
//
// Same exception safety as the normal Copy & Swap.
//
// Usually considered inferor to normal Copy & Swap as the compiler now cannot perform
// copy elision when called with an rvalue. However in the presence of a move assignment
// this is moot as any rvalue will bind to the move-assignment instead.
T& operator=(const T& other) {
using std::swap;
swap(*this, T(other));
return *this;
}
#endif
#if 1
// Copy & Move
//
// Requires move-assignment to be implemented and this to be copy constructible.
//
// Exception safety, same as move assignment operator.
//
// If move assignment is not implemented, the assignment to this in the body
// will bind to this function and an infinite recursion will follow.
T& operator=(const T& other) {
// Clang emits the following if a user or default defined move operator is not present.
// > "warning: all paths through this function will call itself [-Winfinite-recursion]"
// I recommend "-Werror=infinite-recursion" or "-Werror" compiler flags to turn this into an
// error.
// This assert will not protect against missing move-assignment operator.
static_assert(std::is_move_assignable<T>::value, "Must be move assignable!");
// Note that the following will cause clang to emit:
// warning: moving a temporary object prevents copy elision [-Wpessimizing-move]
// *this = std::move(T{other});
// The move doesn't do anything anyway so write it like this;
*this = T(other);
return *this;
}
#endif
#if 1
T& operator=(T&& other) {
// This will cause infinite loop if user defined swap is not defined or findable by ADL
// as the templated std::swap will use move assignment.
// using std::swap;
// swap(*this, other);
name = std::move(other.name);
return *this;
}
#endif
private:
std::string name;
};
的代码我也将增加这个问题的另一种方式来做'operator ='放置new:'T&operator =(const T&other){this->〜T();返回* new(this)T(other); }' – Raxvan
的可能的复制[应复制和交换成语成为复制和移动成语在C++ 11?](http://stackoverflow.com/questions/24014130/should-the-copy-and -swap-idiom-become-the-copy-and-move-idiom-in-c11) –
如果你的移动构造函数抛出异常怎么办?这不会使复制和移动成语不安全? –