C++单例模式中存在static instance资源什么时间被回收的问题

本文探讨了C++单例模式中static实例何时会被回收的问题,并提出使用shared_ptr作为解决方案。
class CSingleton
{
private:
	CSingleton()   //构造函数是私有的
	{
	}
	static CSingleton *m_pInstance;
public:
	static CSingleton * GetInstance()
	{
		if(m_pInstance == NULL)  //判断是否第一次调用
			m_pInstance = new CSingleton();
		return m_pInstance;
	}
};

使用shared_prt来解决这个问题

// ConsoleApplication4.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include<iostream>
#include<string>
#include<map>
#include<vector>
#include<memory>

using namespace std;

class B
{
public :
	B(int  b){ _b = b; }
	int _b;
	~B()
	{
		cout << "释放B"<< _b << endl;
	}
};


class Singleton
{

public:
	~Singleton()
	{
		cout << "释放singleton" << endl;
	}
private:
	Singleton(){ 
		
	};
private:
	static shared_ptr<Singleton> _instance;

public:
	static shared_ptr<Singleton> getInstance();

	void printCode()
	{
		cout << "i am printing" << std::endl;
	}

	vector<B*> bs;
	
};

shared_ptr<Singleton>  Singleton::_instance = nullptr;


shared_ptr<Singleton>  Singleton::getInstance()
{
	 
	if (_instance == nullptr)
		_instance =  shared_ptr<Singleton>(new Singleton());
	return _instance;
	 
}


void testSingleton()
{
	auto s = Singleton::getInstance();
	B b3 (3);
	s->bs.push_back(&b3);  //b3 出函数后会被销毁,所以出了该作用域之后的b调用会有大问题
	for each (auto var in s->bs)
	{
		cout << var->_b << endl;
	}
	
}


int _tmain(int argc, _TCHAR* argv[])
{

	shared_ptr<Singleton>  s = Singleton::getInstance();
	s->printCode();


	B b1 = B(1);
	B b2 = B(2);
	testSingleton();

 
	s->bs.push_back(&b1);
	s->bs.push_back(&b2);

	for each (auto var in s->bs)
	{
		cout << var->_b << endl;
	}


	
	return 0;// Main函数调用结束之后 Singleton的实例会被回收,其资源也会被回收


}


<think> 我们正在讨论Qt C++单例模式的实现方案。根据引用内容,Qt环境下实现单例模式需要考虑线程安全、防止拷贝、全局访问等要素,并且可以使用双重校验锁或者静态局部变量等方式实现。 结合引用内容,我们可以总结出以下几种实现方式: 1. **双重校验锁(Double-Checked Locking)**:这种方式在多线程环境下安全且高效,通过两次检查来确保只创建一个实例,并使用互斥锁保证线程安全。 2. **静态局部变量**:利用C++11的静态局部变量特性(线程安全初始化)来实现懒汉式单例,代码简洁且安全。 3. **饿汉式**:在程序启动时就初始化单例,线程安全但可能增加启动时间。 下面分别给出这三种方式的实现示例: ### 1. 双重校验锁实现(引用[1][3]) ```cpp // MySingleton.h #include <QMutex> #include <QScopedPointer> class MySingleton { public: static MySingleton* getInstance(); // 删除拷贝构造函数和赋值运算符 MySingleton(const MySingleton&) = delete; MySingleton& operator=(const MySingleton&) = delete; private: MySingleton() = default; // 私有构造函数 ~MySingleton() = default; // 私有析构函数 static QMutex mutex; static MySingleton* instance; // 静态实例指针 }; // MySingleton.cpp #include "MySingleton.h" QMutex MySingleton::mutex; MySingleton* MySingleton::instance = nullptr; MySingleton* MySingleton::getInstance() { if (instance == nullptr) { // 第一次检查 QMutexLocker locker(&mutex); // 加锁 if (instance == nullptr) { // 第二次检查 instance = new MySingleton(); } } return instance; } ``` ### 2. 静态局部变量实现(引用[4][5]) 这种方式是线程安全的,因为C++11保证了静态局部变量的初始化是线程安全的。 ```cpp // MySingleton.h class MySingleton { public: static MySingleton* getInstance(); MySingleton(const MySingleton&) = delete; MySingleton& operator=(const MySingleton&) = delete; private: MySingleton() = default; ~MySingleton() = default; }; // MySingleton.cpp #include "MySingleton.h" MySingleton* MySingleton::getInstance() { static MySingleton instance; return &instance; } ``` 或者返回指针(在堆上分配): ```cpp MySingleton* MySingleton::getInstance() { static MySingleton* instance = new MySingleton(); return instance; } ``` 注意:返回指针的方式需要自己管理内存(一般不释放,因为单例是全局的),而返回静态局部对象本身则会在程序结束时自动析构。 ### 3. 饿汉式实现(引用[3]) 在程序启动时就初始化单例,因此不需要考虑线程安全,因为初始化发生在main函数之前(单线程环境)。 ```cpp // MySingleton.h class MySingleton { public: static MySingleton* getInstance(); MySingleton(const MySingleton&) = delete; MySingleton& operator=(const MySingleton&) = delete; private: MySingleton() = default; ~MySingleton() = default; static MySingleton* instance; }; // MySingleton.cpp #include "MySingleton.h" // 在cpp文件中定义并初始化 MySingleton* MySingleton::instance = new MySingleton(); MySingleton* MySingleton::getInstance() { return instance; } ``` ### 使用示例(引用[2][5]) ```cpp #include <QCoreApplication> #include "MySingleton.h" int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); MySingleton* instance = MySingleton::getInstance(); // 使用单例对象... return a.exec(); } ``` ### 注意事项 - **线程安全**:在Qt多线程环境下,双重校验锁和静态局部变量方式都是线程安全的。饿汉式在程序启动时初始化,所以也是线程安全的。 - **内存管理**:双重校验锁和饿汉式返回指针,需要确保在程序结束时正确释放内存(或依赖操作系统回收)。静态局部变量方式在程序结束时自动析构。 - **防止拷贝**:通过删除拷贝构造函数和赋值运算符来防止复制单例对象。 ### 推荐方案 对于Qt应用,推荐使用静态局部变量的方式(C++11标准支持),因为它代码简洁、线程安全且自动管理生命周期(如果是静态对象而不是指针)。但如果需要将单例对象作为QObject派生类(例如需要信号槽),则需要注意QObject的父子关系,此时可能需要使用指针形式,并确保在适当的时候销毁(通常程序结束时销毁,也可以使用QScopedPointer等智能指针管理)。 如果使用QObject派生类,注意不能在静态对象析构时发送信号(因为此时事件循环可能已停止),所以在这种情况下,使用指针形式(不主动销毁)可能更安全,因为程序退出时系统会回收内存,但不会调用析构函数中的信号发送。 ### 相关问题 §§相关问题§§ 1. Qt单例模式中如何管理QObject派生类的生命周期? 2. 静态局部变量实现单例模式C++11中的线程安全机制是什么? 3. 如何实现一个带参数初始化的Qt单例? 4. 单例模式在Qt中的常见应用场景有哪些? 5. 双重校验锁在Qt中需要特别注意哪些问题? </think>### Qt C++ 单例模式实现方案 在 Qt C++ 中实现单例模式有多种方式,下面是三种常用方案及其实现细节: #### 方案一:静态局部变量实现(C++11线程安全) ```cpp // MySingleton.h #include <QObject> class MySingleton : public QObject { Q_OBJECT public: static MySingleton* instance() { static MySingleton instance; return &instance; } void doSomething(); // 示例方法 // 删除拷贝构造和赋值运算符 MySingleton(const MySingleton&) = delete; MySingleton& operator=(const MySingleton&) = delete; private: explicit MySingleton(QObject* parent = nullptr) : QObject(parent) { // 初始化代码 } }; ``` **使用方式**: ```cpp MySingleton::instance()->doSomething(); ``` **特点**: - C++11 保证静态局部变量初始化线程安全 - 简洁高效,自动释放内存 - 适用于大多数场景[^4][^5] #### 方案二:双重校验锁(传统线程安全) ```cpp // MySingleton.h #include <QMutex> #include <QMutexLocker> class MySingleton { public: static MySingleton* getInstance() { if (!m_instance) { QMutexLocker locker(&m_mutex); if (!m_instance) { m_instance = new MySingleton(); } } return m_instance; } void doSomething(); MySingleton(const MySingleton&) = delete; MySingleton& operator=(const MySingleton&) = delete; private: MySingleton() = default; ~MySingleton() = default; static QMutex m_mutex; static MySingleton* m_instance; }; // MySingleton.cpp QMutex MySingleton::m_mutex; MySingleton* MySingleton::m_instance = nullptr; ``` **特点**: - 显式线程安全控制 - 支持延迟初始化 - 需手动管理内存[^1][^3] #### 方案三:Q_GLOBAL_STATIC(Qt 特有) ```cpp // MySingleton.h #include <QGlobalStatic> class MySingleton { public: static MySingleton* instance() { static QGlobalStatic<MySingleton> s_instance; return s_instance; } void doSomething(); MySingleton(const MySingleton&) = delete; MySingleton& operator=(const MySingleton&) = delete; private: MySingleton() = default; }; ``` **特点**: - Qt 框架原生支持 - 自动处理线程安全和销毁 - 适用于 Qt 插件和库开发[^3] ### 通用实现要点 1. **线程安全**: - 使用互斥锁(`QMutex`)或原子操作保证线程安全 - C++11 后静态局部变量默认线程安全 2. **防止拷贝**: ```cpp MySingleton(const MySingleton&) = delete; MySingleton& operator=(const MySingleton&) = delete; ``` 3. **全局访问**: - 提供静态 `instance()` 方法获取唯一实例 - 构造函数设为 `private` 防止外部实例化 4. **内存管理**: - 避免手动 `new`/`delete` - 依赖作用域自动释放(推荐方案一) ### 使用示例 ```cpp #include "MySingleton.h" int main() { // 获取单例实例 MySingleton* singleton = MySingleton::instance(); // 使用单例方法 singleton->doSomething(); return 0; } ``` ### 注意事项 1. **QObject 派生类**:如果单例继承自 `QObject`,需处理父子关系 2. **跨模块使用**:在动态库中需确保单例的唯一性 3. **初始化顺序**:避免静态初始化顺序问题(使用函数局部静态变量) 4. **信号槽系统**:单例可作为全局事件分发器[^5] ```cpp class EventDispatcher : public QObject { Q_OBJECT public: static EventDispatcher* instance() { /*...*/ } signals: void dataUpdated(const QVariant& data); }; ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值