Singleton:如何将析构函数调用两次?

vla*_*don 6 c++ singleton destructor design-patterns

几分钟前我问了一个关于单例实现的问题,我从@LightnessRacesinOrbit得到了非常好的答案.

但是我无法理解为什么在下一个例子中如果我Singleton在变量中实例化inst它的析构函数被调用两次?

#include <iostream>

class Singleton
{
public:
    ~Singleton()  { std::cout << "destruction!\n"; }

    static Singleton& getInstance() 
    {
        static Singleton instance;
        return instance;
    }

    void foo() { std::cout << "foo!\n"; }

private:
    Singleton() { std::cout << "construction!\n"; }
};

int main()
{
    Singleton inst = Singleton::getInstance();
    inst.foo();
}
Run Code Online (Sandbox Code Playgroud)

输出:

construction!
foo!
destruction!
destruction!
Run Code Online (Sandbox Code Playgroud)

现场演示

更正确的是,我理解为什么它会被调用两次.但是,如果在第一个析构函数之后,类的实例被销毁,我无法理解如何调用它两次?为什么没有例外?

还是没有摧毁?为什么?

Cor*_*mer 17

这条线

Singleton inst = Singleton::getInstance();
Run Code Online (Sandbox Code Playgroud)

应该

Singleton& inst = Singleton::getInstance();
Run Code Online (Sandbox Code Playgroud)

然后你只会看到一个析构函数调用.

它的编写方式Singleton::getInstance()返回一个引用,然后将其复制inst.因此,Singleton从您的函数返回的内容副本都将被销毁.你从来没有看到副本被构造,因为没有使用默认构造函数,复制构造函数是.

在第二种方法中,返回引用,然后您只需要inst引用它Singleton而不是复制.

正如其他人所提到的,你可以使这个类不可复制和不可移动以防止这种情况发生

Singleton(Singleton const&) = delete;             // Copy construct
Singleton(Singleton&&) = delete;                  // Move construct
Singleton& operator=(Singleton const&) = delete;  // Copy assign
Singleton& operator=(Singleton &&) = delete;      // Move assign
Run Code Online (Sandbox Code Playgroud)

  • 由于编译器不会自动生成它们,因此无需显式删除rvalue-reference-versions. (3认同)

Dan*_*rey 8

这条线

Singleton inst = Singleton::getInstance();
Run Code Online (Sandbox Code Playgroud)

使用自动生成的复制构造函数复制您的实例.为防止这种情况发生,请添加

Singleton( const Singleton& ) = delete;
Run Code Online (Sandbox Code Playgroud)

到你的班级,以防止这些复制品.为了确保捕捉到更加模糊的错误,还要添加

void operator=( const Singleton& ) = delete;
Run Code Online (Sandbox Code Playgroud)

同样.您不必显式删除移动构造或赋值,因为编译器不会在声明其他(已删除)成员的情况下生成它们.