1

我有下面的简单程序:

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

我试图构建一个简单的三类规则。我在这条线上得到了 UB,Counter z{x};它应该调用复制构造函数。输出:

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++ 以来已经有一段时间了。我只是找不到错误!

4

2 回答 2

3

std::swap如果您定义了一个,则仅使用移动赋值运算符(一旦您添加了几乎任何其他特殊成员函数,编译器将不会定义一个)。你没有,所以它回退到复制分配。

但是您的复制赋值运算符是根据std::swap. 这当然是一个无休止的递归:要交换,您需要分配,要分配,您需要交换。最终你得到一个堆栈溢出。

您可以m_count直接在复制构造函数中初始化(并直接在复制赋值运算符中修改它)。看起来你在做一半的复制和交换习语,但我不确定你在这里的真正目的是什么。

是的,在现代 C++ 中,您还应该在适当的地方实现移动构造函数。如果正确完成,这将修复std::swap递归。我建议您查看一些如何正确实现这些特殊成员函数的示例。

于 2019-09-02T11:50:46.073 回答
2

在我看来,您应该像这样更改您的复制构造函数:

Counter(const Counter& rhs)
{
    m_count=rhs.m_count;
}

就足够了。结果是:

ctor
defctor
dtor
dtor
dtor
Press any key to continue ...
于 2019-09-02T11:53:28.207 回答