我有下面的简单程序:
#include <iostream>
class Counter
{
private:
size_t m_count;
public:
Counter() :
m_count(0)
{
std::cout << "defctor" << '\n';
}
Counter(size_t count) :
m_count(count)
{
std::cout << "ctor" << '\n';
}
~Counter() {
std::cout << "dtor" << '\n';
}
Counter(const Counter& rhs) :
m_count{0}
{
Counter temp{rhs.m_count};
std::cout << "cctor" << '\n';
std::swap(*this, temp);
}
Counter& operator=(const Counter& rhs)
{
if (this == &rhs) {
return *this;
}
Counter temp{rhs.m_count};
std::swap(*this, temp);
std::cout << "caop" << '\n';
return *this;
}
constexpr int getCount() const noexcept {
return this-> m_count;
}
};
int main() {
Counter x{1};
Counter y;
Counter z{x}; // this fails
}
我试图构建一个简单的三类规则。我在这行 Counter z{x};
上得到了 UB,它应该调用复制构造函数。输出:
ctor
defctor
ctor
cctor
ctor
cctor
ctor
cctor
ctor
cctor
ctor
cctor
ctor
cctor
ctor
cctor
ctor
cctor
ctor
cctor
ctor
cctor
ctor
cctor
ctor
cctor
ctor
然后它重复 ctor\ncctor
...
我已经有一段时间没有使用 C++ 了。我就是找不到错误!
最佳答案
std::swap
仅在您定义了一个移动赋值运算符时才使用它(一旦您添加了几乎任何其他特殊成员函数,编译器将不会定义一个)。你没有,所以它退回到复制作业。
但是您的复制赋值运算符是根据 std::swap
定义的。这当然是一个无穷无尽的递归:要交换你需要赋值,而赋值你需要交换。最终你会遇到堆栈溢出。
您可以直接在复制构造函数中初始化m_count
(并直接在复制赋值运算符中修改它)。看起来你正在做一半的 copy-and-swap 习语,但我不确定你在这里真正要做什么。
是的,在现代 C++ 中,您还应该在适当的地方实现移动构造函数。如果操作正确,这将修复 std::swap
递归。我建议您查看一些示例,了解如何正确实现这些特殊成员函数。
关于c++ - 使用复制构造函数创建对象(三类简单规则)会产生运行时错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57756101/