c++ - 使用复制构造函数创建对象(三类简单规则)会产生运行时错误

标签 c++ runtime-error copy-constructor undefined-behavior rule-of-three

我有下面的简单程序:

#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/

相关文章:

android - 启动模拟器和安卓设备时出错

c++ - 强制复制构造函数而不是移动构造函数

c++ - 复制构造函数不是继承的

c++ - 如何检查进程是否仍在 Windows Server 2008 上运行?

c++ - XCode 5 不会破坏 C++ 模板

c++ - 不能包含 boost.asio

即使在格式化输入后,uva在线判断中的JAVA运行时错误

html - observe.js 中的纸张下拉菜单错误

c++ - RValue、模板解析和复制构造函数(在 Visual C++ 2010 中)

c++ - 生成E=0的浮点随机数