使用模板并调用析构函数的singleton

singleton using template and calling destructor

本文关键字:析构函数 singleton 调用      更新时间:2023-10-16

我有一个单例类实现如下。

#include <iostream>
using namespace std;
template<class T>
class singleton{
protected:
    static T* s_instance;
public:
    T* instance(){
        if(s_instance){
            return s_instance ;
        }else{
           s_instance = new T;
           return s_instance;
        }
    }
};
template <class T>
T* singleton<T>::s_instance;
class A:public singleton<A>{
    friend class singleton;
public:
  void print_add(){
    cout<<"I AM A"<<endl;
    cout<<s_instance<<endl;
  }
  ~A(){
      //delete s_instance;
      cout<<"Dest A"<<endl;
   }
private:
    A(){}
};
class B:public singleton<B>{
    friend class singleton;
public:
  void print_add(){
    cout<<"I AM B"<<endl;
    cout<<s_instance<<endl;
 }
 ~B(){
       cout<<"Dest B"<<endl;
       //delete s_instance;
  }
private:
    B(){}
};
int main(){
    A* a, *c;
    B* b;
    a->instance()->print_add();
    b->instance()->print_add();
    c->instance()->print_add();     
}

如何为此调用析构函数。看起来,如果没有上面的"删除"行,valgrind显示0个内存泄漏。如果不删除指针,我是否泄漏了内存?或者实现singleton的方法是错误的?对于这两个类,我们有一个公共的静态成员。基本上,静态成员对于不同的对象有什么不同?

感谢

对于每个T,都有自己的singleton类专门化,它有自己的静态数据成员。所以对于A和B来说,这些是不同的。

你确实会泄露内存。有几种方法可以解决这个问题。如果你想保持懒惰的初始化,可以使用std::unique_ptr作为s_instance。然后对象将被正确地销毁。请注意,您的初始化不是线程安全的。

您也可以只使用:T s_instance而不是T* s_instance。通过这种方式,对象在main()之前被构造,并且也将被正确地销毁。这也意味着这是线程安全的。

另一种方法是将static T s_instance;直接放在instance()方法中并返回它。这在C++11中是线程安全的。

有几件事值得注意:

实际上,你没有泄露记忆。只能创建该类的单个实例(这意味着泄漏不可能导致过度使用资源),并且当客户端进程终止时,OS将获得分配给该实例的内存。

确保在程序终止期间删除单例实例(而不是由操作系统获取)的最简单方法就是使用具有函数范围的静态实例:

template<class T>
struct Singleton {
  static T& instance() {
    static T instance_;
    return instance_;
  }
};
class SingletonClient : public Singleton<SingletonClient> {
  friend class Singleton<SingletonClient>;
  SingletonClient()
  {}
};
SingletonClient &s = Singleton<SingletonClient>::instance();

使用模板实现singleton有一些微妙之处。如果您在多个翻译单元中使用单例模板实例化,那么当您真正只想要一个实例时,实际上可能会得到多个单例客户端实例。处理此问题的方法是在客户端类的头文件中使用extern模板声明,并在客户端的实现文件中使用模板实例化。

// In header file of SingletonClient:
extern template class Singleton<SingletonClient>;
// In the implementation file of SingletonClient:
template class Singleton<SingletonClient>;