2.单例模式

发布于:2025-07-13 ⋅ 阅读:(16) ⋅ 点赞:(0)

一、定义

确保一个类只有一个实例, 并提供一个访问该实例的全局节点。

二、要解决的问题

  • 单一实例
    无论new了多少个对象,始终只存在一个实例
  • 应用场景
    对临界资源(例如日志、打印机)的访问

三、解决步骤

  1. 将默认构造函数声明成私有类型,防止其他对象使用单例类的new运算符
  2. 新建一个静态构建方法作为构造函数。
  3. 该静态函数会调用私有构造函数来创建对象, 并将其保存在一个静态成员变量中。 此后所有对于该函数的调用都将返回这一缓存对象。

四、应用场景

  • 如果程序中的某个类对于所有客户端只有一个可用的实例,使用单例模式
    • 单例模式禁止通过除特殊构建方法以外的任何方式来创建自身类的对象。
    • 该方法可以创建一个新对象, 但如果该对象已经被创建, 则返回已有的对象
  • 如果需要更加严格地控制全局变量,可以使用单例模式
    • 单例模式与全局变量不同,它保证类只存在一个实例。
    • 除了单例模式以外,无法通过任何方式替换缓存的实例

五、代码实现

4.1 实现方法1

下面这种方式存在以下问题

  • 只提供了getInstance方法获取对象,没有提供释放函数
  • 析构函数不会被运行,可以使用智能指针替代原指针
  • 多线程调用getInstance时将使用来保证安全
#include <iostream>
#include <mutex>
#include <thread>

class Singleton
{
private:
	static Singleton* m_singleton;  //实例对象为私有
	static std::mutex m_mutex;

	Singleton()  //构造方法为私有
	{
		std::cout << "Singleton" << std::endl;
	}

	~Singleton()
	{
		std::cout << "~Singleton" << std::endl;
	}

	//禁用拷贝构造函数和赋值运算符
	Singleton(const Singleton& obj) = delete;
	Singleton& operator=(const Singleton& obj) = delete;

public:
	static Singleton* getInstance()
	{
		std::lock_guard<std::mutex> lock(m_mutex); //添加线程锁
		if (!m_singleton)
		{
			m_singleton = new Singleton();
		}

		return m_singleton;
	}

	void printAddress(const std::string& preString)
	{
		printf("%s: %p\n", preString.c_str(), this);
	}
};

Singleton* Singleton::m_singleton = nullptr;
std::mutex Singleton::m_mutex;

void ThreadFunc()
{
	std::this_thread::sleep_for(std::chrono::milliseconds(1000));
	Singleton* single = Singleton::getInstance();
	
	single->printAddress("ThreadFunc");
}

void ThreadFunc2()
{
	std::this_thread::sleep_for(std::chrono::milliseconds(1000));
	Singleton* single = Singleton::getInstance();

	single->printAddress("ThreadFunc2");
}

int main()
{
	std::thread t1(ThreadFunc);
	std::thread t2(ThreadFunc2);

	t1.join();
	t2.join();
	return 0;
}

4.2 实现方法2

改进点

  • 采用局部静态变量的方式返回,线程安全(c++11及以后)
  • 没有采用new关键字在堆空间中申请内存,空间被自动管理
  • 析构函数被自动执行
  • 下面是Singleton类的实现,其它函数保持原样
#include <iostream>
#include <mutex>
#include <thread>

class Singleton
{
private:

	Singleton()  //构造方法为私有
	{
		std::cout << "Singleton" << std::endl;
	}

	~Singleton()
	{
		std::cout << "~Singleton" << std::endl;
	}

	//禁用拷贝构造函数和赋值运算符
	Singleton(const Singleton& obj) = delete;
	Singleton& operator=(const Singleton& obj) = delete;

public:
	//返回指针可能被误delete,直接返回引用
	static Singleton& getInstance()
	{
		static Singleton m_signleton;

		return m_signleton;
	}

	void printAddress(const std::string& preString)
	{
		std::cout << preString << " : " << this << std::endl;
	}
};

void ThreadFunc()
{
	std::this_thread::sleep_for(std::chrono::milliseconds(1000));
	Singleton& single = Singleton::getInstance();
	
	single.printAddress("ThreadFunc");
}

void ThreadFunc2()
{
	std::this_thread::sleep_for(std::chrono::milliseconds(1000));
	Singleton& single = Singleton::getInstance();

	single.printAddress("ThreadFunc2");
}

int main()
{
	std::thread t1(ThreadFunc);
	std::thread t2(ThreadFunc2);

	t1.join();
	t2.join();

	return 0;
}

网站公告

今日签到

点亮在社区的每一天
去签到