我实现了一个单例类,如下所示。
#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内存泄漏。没有删除指针,我泄漏了内存吗?或者实施单身人士的方法是错误的? 对于这两个类,我们有一个共同的静态成员。基本上静态成员在这里对不同的对象有何不同?
由于
答案 0 :(得分:2)
有一些值得注意的事情:
实际上,你并没有泄露记忆。只能创建该类的一个实例(这意味着泄漏无法导致过多的资源使用),并且当客户端进程终止时,操作系统将获得分配给该实例的内存。
确保在程序终止期间删除单例实例的最简单方法,与操作系统获取相反,只是使用具有函数范围的静态实例:
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();
使用模板实现单例有一些微妙之处。如果您在多个翻译单元中使用单例模板实例化,那么当您真正只想要一个单例客户端时,您实际上最终可能会得到多个单例客户端实例。处理此问题的方法是在客户端类的头文件中使用extern模板声明,在客户端的实现文件中使用模板实例化。
// In header file of SingletonClient:
extern template class Singleton<SingletonClient>;
// In the implementation file of SingletonClient:
template class Singleton<SingletonClient>;
答案 1 :(得分:2)
对于每个T,都有它自己的单例类特化,它有自己的静态数据成员。所以对于A和B来说,这些是不同的。
你的内存泄漏了。并且有几种方法可以解决它。如果要保持延迟初始化,请将sd :: unique_ptr用于s_instance。然后对象将被正确销毁。请注意,您的初始化不是线程安全的。
您也可以只使用T s_instance
代替T* s_instance
。这样,对象在main()之前构造,并且也将被正确地破坏。这也意味着这是线程安全的。
另一种方法是在instance()方法中使用static T s_instance;
并返回它。这保证在C ++ 11中是线程安全的。