static unique_ptr两次调用析构函数

时间:2016-03-26 21:24:03

标签: c++ c++11 singleton lazy-loading unique-ptr

我使用单例模式返回对unique_ptr dereference的引用。这是代码,

#include <iostream>
#include <memory>
using std::cout; using std::endl;
using std::unique_ptr;

namespace Settings {
    class Lazy {
        Lazy() { cout << "Lazy::Lazy() " << this << endl; }
    public:
        ~Lazy() { cout << "Lazy::~Lazy() " << this << endl; }
        static Lazy &instance()
        {
            static unique_ptr<Lazy> lazy(new Lazy);
            return *lazy;
        }
    };

    Lazy &lazy()
    { return Lazy::instance(); }
}

int main()
{
    cout << "main starts!" << endl;
    auto state = Settings::lazy();
    cout << "auto state = Settings::lazy() " << &state << endl;

    cout << "main ends!" << endl;
    return 0;
}

我原以为类的析构函数只会调用一次,但是构造函数调用一次析构函数调用两次,这里是输出,

main starts!
Lazy::Lazy() 0xb1ec20
auto state = Settings::lazy() 0x7ffe17ae18b8
main ends!
Lazy::~Lazy() 0x7ffe17ae18b8
Lazy::~Lazy() 0xb1ec20

为什么析构函数会调用两次?甚至第二次呼叫这个地址也不同。

3 个答案:

答案 0 :(得分:4)

因为你有2个单例实例,并且都被破坏了。

你需要2个单身的原因是,当你获得单身auto state = Settings::lazy();时,会创建一个副本。您可能会返回引用,但state不是引用,因此会创建副本。

使state引用可修复问题:auto& state = Settings::lazy();

答案 1 :(得分:1)

Rakete1111解决方案是正确的,但是您可能还想删除单例的副本构造函数和副本分配。这样,您就可以防止发生此类错误。

答案 2 :(得分:1)

Singleton 类必须禁用任何复制/移动构造函数和赋值/移动运算符。 否则这不是单例。
因此,

Lazy(Lazy &) = delete;
Lazy(Lazy &&) = delete;
Lazy &operator=(Lazy &) = delete;
Lazy &operator=(Lazy &&) = delete;

那么以下将是唯一有效的操作:

auto& state = Settings::lazy();