交换和移动无限递归
swap and move infinite recursion
我有一个非常简单的示例 class,使用 C++17 编译。
#include <string>
#include <iostream>
struct name {
std::string first, middle, last;
name() = default;
name(name const&) = default;
name(name &&) = default;
name& operator=(name o) {
std::swap(*this, o); // bad!
return *this;
}
};
int main() {
name n1{"mr", "john", "smith"};
name n2 = std::move(n1);
name n3 = n2;
std::cout << n3.first << " " << n3.middle << " " << n3.last;
}
使用这个值语义,捆绑移动赋值,我故意调用合格的交换,而不是 using std::swap; swap(*this, o);
。反正我没有提供交换。考虑到 STL 将交换实现为一个移动构造和一系列移动分配,我认为这个实现将无限递归,交换调用移动和移动调用交换。 std::swap
是否更改为成员交换或类似的东西?
您从未调用过operator=
;您所有的代码都使用 initialization (which invokes constructors), specifically copy initialization,而不是赋值(调用 operator=
)。
将代码更改为:
name n1{"mr", "john", "smith"};
name n2, n3;
n2 = std::move(n1);
n3 = n2;
你会看到你的 operator=
被使用(并且可能会爆炸)。
鉴于您还没有定义自己的 swap()
,写 std::swap(*this, o);
或 using std::swap; swap(*this, o);
是一样的(在您的代码示例的框架内)并且真的没有强调这样写的意图:在没有 ADL 的情况下,std::swap
版本将在两种情况下使用。
在你的声明中:
name n2 = std::move(n1);
name n3 = n2;
operator=()
永远不会被调用,初始化将仅使用您的 class 构造函数完成。
我有一个非常简单的示例 class,使用 C++17 编译。
#include <string>
#include <iostream>
struct name {
std::string first, middle, last;
name() = default;
name(name const&) = default;
name(name &&) = default;
name& operator=(name o) {
std::swap(*this, o); // bad!
return *this;
}
};
int main() {
name n1{"mr", "john", "smith"};
name n2 = std::move(n1);
name n3 = n2;
std::cout << n3.first << " " << n3.middle << " " << n3.last;
}
使用这个值语义,捆绑移动赋值,我故意调用合格的交换,而不是 using std::swap; swap(*this, o);
。反正我没有提供交换。考虑到 STL 将交换实现为一个移动构造和一系列移动分配,我认为这个实现将无限递归,交换调用移动和移动调用交换。 std::swap
是否更改为成员交换或类似的东西?
您从未调用过operator=
;您所有的代码都使用 initialization (which invokes constructors), specifically copy initialization,而不是赋值(调用 operator=
)。
将代码更改为:
name n1{"mr", "john", "smith"};
name n2, n3;
n2 = std::move(n1);
n3 = n2;
你会看到你的 operator=
被使用(并且可能会爆炸)。
鉴于您还没有定义自己的
swap()
,写std::swap(*this, o);
或using std::swap; swap(*this, o);
是一样的(在您的代码示例的框架内)并且真的没有强调这样写的意图:在没有 ADL 的情况下,std::swap
版本将在两种情况下使用。在你的声明中:
name n2 = std::move(n1); name n3 = n2;
operator=()
永远不会被调用,初始化将仅使用您的 class 构造函数完成。