管理单例析构函数

时间:2011-08-09 08:33:59

标签: c++ c++11

以下小例子实现了我多次见过的单例模式:

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

我遇到的主要问题是我的单身人士的析构函数永远不会被调用。

我可以改为instance a(c ++ 0x?)shared_ptr,这很有效 - 除非它意味着我的析构函数必须公开。

我可以添加静态'清理'方法,但这会打开用户错误的可能性(即忘记调用它)。面对(未处理的)例外,它也不允许进行适当的清理。

是否存在允许延迟实例化的常见策略/模式,“自动”调用我的析构函数,并且仍允许我将析构函数保密:

6 个答案:

答案 0 :(得分:20)

......不完全是一个直接的答案,但是评论的时间太长了 - 为什么不这样做单身人士呢?

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

public:
  static SingletonTest& get_instance()  {
    static SingletonTest instance;
    return instance;
  }
};

现在你有一个懒惰的单身人士将在退出时被破坏......它不会比你的代码重入......

答案 1 :(得分:2)

您可以编写一个deinitialization函数并在对象构造函数中调用atexit()来注册它。然后,当C ++运行时取消初始化模块时,它会在main() 调用您的取消初始化函数后的某个时刻 。那个大胆的斜体就是因为你对它的确切调用时间有了相当松散的控制,并且可能导致取消初始化秩序惨败 - 小心。

答案 2 :(得分:1)

你总是可以使用shared_ptr(或更确切地说是scoped_ptr,它更合适)来允许它访问你的私有析构函数。

请注意,还有系统atexit()函数,它可以在应用程序结束时注册要调用的函数。你可以传递你的单身的静态函数delete instanance;

请注意,将单个类与单例类分开是一个好主意。特别是对于测试和/或当你需要双重测试时。 :)

当我在它时,尽量避免延迟初始化。在启动时以明确的顺序初始化/创建您的单身人士。这允许他们正确关闭并解决依赖性而不会出现意外。 (我有循环单身地狱......这比你想象的容易......)

答案 3 :(得分:1)

您可以使用具有shared_ptr的私有析构函数,方法是传入一个可以访问析构函数的删除器(例如定义为SingletonTest成员的类)。

但是,在销毁单身人士以确保他们在被摧毁后不被使用时,你需要非常小心。为什么不使用普通的全局变量?

答案 4 :(得分:1)

如果你声明实际delete op作为朋友(让它为shared_ptr<SingletonTest>或某种默认删除者)的朋友,你的析构函数可以是私有的。 虽然我没有看到任何将其私有化的必要性。

答案 5 :(得分:0)

第一个问题是:你想要破坏单身人士吗? 破坏单身可能会导致破坏问题;和 因为你正在关闭,所以析构函数是不必要的 维护程序不变量。关于你唯一想要运行的时间 单例的析构函数是它管理系统的资源 不会像临时文件那样自动清理。否则,就是这样 更好的策略是不要在其上调用析构函数。

鉴于此,如果您想要调用析构函数,则有两个 替代方案:将单个对象声明为静态局部变量 instance函数,或使用std::auto_ptr或类似的东西, 而不是原始指针,作为指向它的指针。