// 单例模式是一种设计模式,它保证一个类只有一个实例,并提供一个全局访问点
// 在c++中,单例模式可以通过类的静态成员变量和静态成员函数实现,构造函数为私有成员函数
// 1.只有一个实例,即全局唯一
// 2.可以在程序的任何地方访问
// 1.线程安全问题:
// 如果多个线程同时调用getInstance()函数,可能会导致多个实例被创建
// 为了解决这个问题,可以使用线程安全的实现方式,例如使用互斥锁或原子操作来保证只有一个线程可以创建实例
// 2.内存泄漏问题:
// 如果单例对象没有正确的被销毁,可能导致内存泄漏
// 为了避免这个问题,可以在单例类中添加析构函数来释放资源
// 3.可维护性问题:
// 单例模式可能会导致代码的可维护性变差,因为它将对象的创建和访问耦合在一起
// 应用场景:
// 适用于全局唯一的对象场景,入日志系统,配置文件管理器等
#include <iostream>
#include <string>
using namespace std;
class Logger {
public:
// 1. 将 `getInstance` 定义为静态成员函数即可在不创建对象的情况下调用;
// 2. 如果需要使用该类的实例,可以将成员函数定义为非静态成员函数,并创建实例来调用该函数;
// 3. 如果不需要使用该类的实例,推荐将 Logger 设计为一个只包含静态成员函数的单例类,以避免对象创建的开销和错误使用。
// 静态局部变量instance用于存储单例,这保证了在程序运行期间只有一个单例被创建
static Logger & getInstance() {
static Logger instance;
return instance;
}
void log(const std::string &message) {
m_log += message;
std::cout << "log:\n" << m_log << std::endl;
}
private:
// 构造函数私有化,防止外部创建实例
Logger() {}
~Logger() {}
// 禁止使用拷贝构造函数创建Logger的副本对象
// =delete的含义是显示删除,可以用于禁止某些函数的使用
// 包括默认的拷贝构造/移动构造/拷贝赋值运算符/移动赋值运算符等
// 这个特性可以确保代码的正确性和安全性
Logger(const Logger &) = delete;
// 禁止使用拷贝赋值运算符来复制Logger的对象
Logger & operator = (const Logger &) = delete;
std::string m_log;
};
int main()
{
// 1. 将 `getInstance` 定义为静态成员函数即可在不创建对象的情况下调用;
// 所有信息都打印到一个对象上,就是单例模式的体现
Logger &log1 = Logger::getInstance();
log1.log("aaaaa\n");
Logger &log2 = Logger::getInstance();
log2.log("bbbbb\n");
Logger::getInstance().log("ccccc\n");
Logger::getInstance().log("ddddd\n");
return 0;
}
#include <iostream>
#include <string>
using namespace std;
// 定义一个单例模式的任务队列
class TaskQueue {
public:
// 静态成员函数可以通过对象、类名、类的对象指针和类的对象引用进行访问,因为静态成员函数是和类相关但和对象无关的。
// 可以使用对象名.`静态成员函数名`、类名.`静态成员函数名`、对象指针名->`静态成员函数名` 和对象引用.`静态成员函数名` 的方式访问。
// 非静态成员函数不能直接通过类来访问,因为非静态成员函数是与对象关联的,需要通过对象或对象指针/引用来调用。
// 可以使用对象名.`非静态成员函数名`、对象指针名->`非静态成员函数名` 和对象引用.`非静态成员函数名` 的方式访问。
// 因为非静态成员函数中可能会访问对象的状态,而类无法代表一个具体的对象,所以不能直接通过类来访问非静态成员函数。
static TaskQueue *getInstance() {
if (m_taskQ == nullptr)
{
m_taskQ = new TaskQueue();
}
return m_taskQ;
}
void print() {
std::cout << "this is a singleton member..." << std::endl;
}
private:
// 为了不能再外边创建该类的任何对象,需要显示的删除掉构造函数,拷贝构造函数以及对象赋值
TaskQueue() = default;
TaskQueue(const TaskQueue &) = delete;
TaskQueue & operator = (const TaskQueue &) = delete;
// 只能通过类名访问静态属性或方法
static TaskQueue *m_taskQ;
};
// 静态变量必须再类外边进行初始化,不能再类里边进行初始化
TaskQueue *TaskQueue::m_taskQ = new TaskQueue();
int main()
{
TaskQueue *task = TaskQueue::getInstance();
task->print();
TaskQueue::getInstance()->print();
return 0;
}
// 单例模式
// 应用场景:
// 配置管理,日志记录,线程池,连接池,对象池,消息队列
// 实现步骤:
// 1.将类的构造方法定义为私有方法
// 2.定义一个私有类的静态实例,保存一个全局唯一的静态实例
// 3.提供一个共有的获取实力的静态方法
// 知识点:
// 1.static静态成员数据
// 2.static静态成员函数
// 3.template模板类
// 4.fridnd友元类
#include <iostream>
#include <string>
using namespace std;
class A {
public:
static A *instance() {
if (m_instance == nullptr)
{
m_instance = new A();
}
return m_instance;
}
void show() {
std::cout << m_name << std::endl;
}
private:
A() : m_name("A") {}
~A() {}
A(const A &) = delete;
A & operator = (const A &) = delete;
private:
std::string m_name;
static A * m_instance;
};
// 静态成员和静态成员函数需要在类外初始化
// 注意需要加上作用域运算符A::,表示该静态成员数以类A
A * A::m_instance = nullptr;
int main()
{
A::instance()->show();
return 0;
}
#include <iostream>
#include <string>
namespace utility {
namespace singleton {
template <typename T>
class Singleton {
public:
static T *instance() {
if (m_instance == nullptr)
{
m_instance = new T();
}
return m_instance;
}
private:
Singleton() {}
~Singleton() {}
Singleton(const Singleton<T> &) = delete;
Singleton<T> & operator = (const Singleton<T> &) = delete;
private:
static T *m_instance;
std::string m_name;
};
// 模板的特殊写法,类的静态成员需要再类外初始化
template <typename T>
T * Singleton<T>::m_instance = nullptr;
}
}
class A {
// 声明Singleton这个模板类为A类一个友元类,模板参数为A
friend class utility::singleton::Singleton<A>;
public:
void show() {
std::cout << m_name << std::endl;
}
private:
A() : m_name("A") {}
~A() {}
A(const A &) = delete;
A & operator = (const A &) = delete;
private:
std::string m_name;
};
class B {
// 声明Singleton这个模板类为A类一个友元类,模板参数为B
friend class utility::singleton::Singleton<B>;
public:
void show() {
std::cout << m_name << std::endl;
}
private:
B() : m_name("B") {}
~B() {}
B(const B &) = delete;
B & operator = (const B &) = delete;
private:
std::string m_name;
};
int main()
{
utility::singleton::Singleton<A>::instance()->show();
utility::singleton::Singleton<B>::instance()->show();
// 关于线程安全问题,可以通过全局只创建一次进行全局调用的方式规避线程安全问题
// 避免引入繁琐的机制导致程序维护变得困难
return 0;
}