1、例子
如果单例对象是类的static成员,那么在程序结束时不会调用类的析构函数,如下:
#include <iostream>
using namespace std;
class A{
private:
static A* m_ins;//声明,静态指针成员
A(){}
public:
static A* getIns(){
if(m_ins==NULL){
m_ins=new A();
}
return m_ins;
}
void test(){
cout<<"testA\n";
}
~A(){
cout<<"~A destruction\n";
}
};
A* A::m_ins=nullptr;//定义
int main()
{
A* a=A::getIns();
a->test();
return 0;
}
输出:
testA
需要在返回前单独添加delete A; 否则是会有内存泄漏的风险的,不过上述的例子,程序结束后,操作系统会回收。
使用new创建对象,需要开发人员手动管理。如果不执行delete,对象和分配的内存将一直存在,直到程序退出后,才由操作系统回收。
将静态指针成员改为函数内的静态变量:
class A{
private:
A(){}
public:
static A& getIns(){//返回引用
static A m_a; // C++11 引入的线程安全的静态变量初始化
return m_a;
}
static A* getIns(){
static A m_a;
return & m_a;
}
};
int main()
{
A::getIns().test();
return 0;
}
#输出:
-> % ./Demo
testA
~A destruction
如果使用如下:
static A* getIns(){
static A* m_a;
if(m_a==nullptr){
m_a = new A();
}
return m_a;
}
main:
A::getIns()->test();
析构函数依旧不会被执行。
2.方法
还可以在内部定义GC类,GC类的析构函数专门用来delete变量。参考:单例模式的析构问题和线程安全问题 | 烫
或者根据 GCC 的 __attribute__((destructor))
特性,在程序退出阶段(main
函数结束或 exit()
被调用时)会自动调用 _delete()
。_delete()
负责释放单例实例的内存。
- 如果没有特殊需求,建议使用静态局部变量实现单例(方式 1)。这种方法最简单,并且是现代 C++ 中的推荐实践。
- 如果需要明确控制析构时间,推荐使用
atexit()
注册析构函数(方式 4)