C++ 管理单例析构函数

C++ 管理单例析构函数,c++,c++11,C++,C++11,下面的小示例实现了我见过很多次的单例模式: #include <iostream> class SingletonTest { private: SingletonTest() {} static SingletonTest *instance; ~SingletonTest() { std::cout << "Destructing!!" << std::endl; } public: static SingletonTest

下面的小示例实现了我见过很多次的单例模式:

#include <iostream>

class SingletonTest {
private:
  SingletonTest() {}
  static SingletonTest *instance;
  ~SingletonTest() {
    std::cout << "Destructing!!" << std::endl;
  }

public:
  static SingletonTest *get_instance()  {
    if(!instance) instance = new SingletonTest;
    return instance;
  }
};

SingletonTest *SingletonTest::instance = 0;

int main(int argc, char *argv[]) {
  SingletonTest *s = SingletonTest::get_instance();

  return 0;
}
#包括
类单音测试{
私人:
SingletonTest(){}
静态SingletonTest*实例;
~SingletonTest(){

STD::CUT< P>可以写一个去初始化函数,调用对象构造函数中的“代码> ATEXIT()/<代码>登记C++。调用您的去初始化函数。之所以使用粗体斜体,是因为您对何时调用该函数的控制非常松散,这可能会导致去初始化顺序失败-请小心。

您可以始终将共享的\u ptr(或者更合适的范围化的\u ptr)作为好友,以允许它访问您的私有析构函数

请注意,还有system
atexit()
函数,它可以注册一个函数以在应用程序结束时调用。您可以向它传递一个singleton的静态函数,该函数只执行
delete Instance;

请注意,将要成为单例的类与它的单例性分开通常是一个好主意。尤其是在测试和/或您确实需要双例时。:)


当我这样做的时候,尽量避免延迟初始化。在启动时,以一个确定的顺序初始化/创建你的单例。这样可以让它们正确关闭并解决依赖关系,而不会让人感到意外。(我经历了循环单例地狱…比你想象的要容易…)

…这不是一个直接的答案,但是评论太长了-为什么不这样做呢

class SingletonTest {
private:
  SingletonTest() {}
  ~SingletonTest() {
    std::cout << "Destructing!!" << std::endl;
  }

public:
  static SingletonTest& get_instance()  {
    static SingletonTest instance;
    return instance;
  }
};
类单音测试{
私人:
SingletonTest(){}
~SingletonTest(){

std::cout您可以通过传入一个可以访问析构函数的删除程序(例如定义为
SingletonTest
成员的类),将私有析构函数与
shared_ptr
一起使用


但是,在销毁单例时需要非常小心,以确保它们在销毁后不会被使用。为什么不使用普通的全局变量呢?

如果您将执行实际的
删除操作的类声明为好友(让它成为
共享的\u ptr
或某种默认的删除器)朋友,你的析构函数可以是私人的。
尽管我不认为有必要将其私有化。

第一个问题是:你想破坏单例吗。 破坏一个单态可导致破坏顺序问题;以及 由于您正在关闭,因此不需要使用析构函数 维护程序不变量。大约只有在您想要运行 单例的析构函数是指它是否管理系统需要的资源 不会像临时文件那样自动清理。否则 更好的策略是不要对其调用析构函数

因此,如果希望调用析构函数,有两个 备选方案:将单个对象声明为中的静态局部变量 使用
实例
函数,或使用
std::auto_ptr
或类似功能,

而不是一个原始指针,作为指向它的指针。

为什么要对单例调用析构函数?@Luchian Grigore:例如,它可以维护一些需要处理的外部资源。有一篇好文章“杀死单例”在John Vlissides的C++报告中,你可以在这里找到文本:谢谢@基因——我会读到的。我读到某个地方“SpopEdTpTR”被从C++ 0x中删除……McKe:我不能得到朋友的方法。我做错了什么?@ BJ Orn:我的坏。,所以您需要将其作为朋友。请查看错误消息指向的源代码。@Björn:您需要执行类似以下操作-->>“friend void boost::checked_delete(Test*x);”--但是,由于中描述的编译器不支持,我不得不满足于-->>“template friend void boost::checked_delete(T*)”这个函数可能是一个静态私有方法吗?否则它类似于将析构函数公开。@sje397:是的,如果它有匹配的签名。我喜欢这个方法。我不太喜欢静态局部变量,但考虑到其他方法,这很好。@sje397,我想这大概是我唯一一次使用它们(静态局部变量),但像往常一样,最好的建议是尽可能完全避免全局性…;)+1我从不使用成员,而是使用静态本地。它还避免了多线程初始化的问题。@Antonio-how?(我的意思是它如何避免多线程初始化的问题,上面的不是线程安全的)@Antonio:这在C++03中是非标准的,但这仅仅是因为C++03标准没有提到线程。任何像样的编译器都已经使这个线程安全。如果方法是内联的(并且没有在.cpp文件中定义),我在Windows(DLL)上对这个习惯用法有问题,因为每个DLL都有它自己的局部静态变量……但它是用VC++03编写的,所以从那以后情况可能发生了变化。我想维护惰性实例化。将析构函数设置为私有的原因与将构造函数设置为私有的原因是一样的:这样对象的生存期就不会受到其他代码的影响。@sje397:nOble目标,但我认为它是非常明显的,由SuntLon类返回的引用可能不会被转换为指针并被删除。如果使用API的家伙做了这样的事情,那么你将很难为他们完成完整的API(特别是因为C++允许在const对象上调用<代码>删除<代码>)。叫我痴迷,但讨厌把事情弄得乱七八糟,或者是依赖于操作系统。C++中的依赖关系的困难应该被整理出来。例如,您的内存(包括静态内存和代码所在的内存)。有许多事情系统不会自动为您执行,例如停止spaw