使用模板并调用析构函数的singleton
singleton using template and calling destructor
我有一个单例类实现如下。
#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>;
- 什么时候调用组成单元对象的析构函数
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 内联映射初始化的动态atexit析构函数崩溃
- 什么时候调用析构函数
- 优先顺序:智能指针和类析构函数
- C++-明确何时以及如何调用析构函数
- 使用基类指针创建对象时,缺少派生类析构函数
- 在c++中使用向量时,如何调用构造函数和析构函数
- 重载运算符new[]的行为取决于析构函数
- 我需要知道编译器如何在cpp中使用析构函数
- 为什么在使用转换构造函数赋值后调用C++类的析构函数?
- 析构函数调用
- 通过引用传递-为什么要调用这个析构函数
- 对具有动态分配的内存和析构函数的类对象的引用
- 重载 -> shared_ptr 个实例中的箭头运算符<interface>,接口中没有纯虚拟析构函数
- C++成员的析构函数顺序与shared_ptr
- Singleton模式中的手动析构函数调用:调用多次
- Singleton模式析构函数C++
- 使用模板并调用析构函数的singleton
- Singleton:析构函数怎么能被调用两次