跳转到内容
新建笔记

单例模式(Singleton Pattern)

单例模式(Singleton Pattern) 任务管理器可以作为一个全局的任务配置管理类,使用单例模式保证全局只有一个实例。这样你可以避免在应用程序中创建多个任务管理对象,保持配置参数的统一。

class TaskManager {
private:
static TaskManager *instance;
TaskManager() {} // 私有构造函数
public:
static TaskManager* getInstance() {
if (instance == nullptr) {
instance = new TaskManager();
}
return instance;
}
// 任务管理方法
void saveTaskTemplate(const TaskParameters &task, const QString &filename) {
task.saveToFile(filename);
}
// 其他任务方法...
};
TaskManager* TaskManager::instance = nullptr;

或者

class SystemConfig {
public:
// 提供一个全局访问点,返回唯一的实例
static SystemConfig& instance() {
static SystemConfig instance; // 静态局部变量,确保只初始化一次
return instance;
}
// 系统配置相关参数
QString systemSetting1;
int systemSetting2;
// 设置和获取系统配置的方法
// 可以在这里添加一些方法来操作配置参数
private:
// 私有构造函数,确保外部不能直接创建实例
SystemConfig() {}
// 禁用复制构造函数
SystemConfig(const SystemConfig&) = delete;
// 禁用赋值运算符
void operator=(const SystemConfig&) = delete;
};
#include <iostream>
#include <QString>
int main() {
// 获取单例实例
SystemConfig& config = SystemConfig::instance();
// 设置配置参数
config.systemSetting1 = "Hello, World!";
config.systemSetting2 = 42;
// 输出配置参数
std::cout << "System Setting 1: " << config.systemSetting1.toStdString() << std::endl;
std::cout << "System Setting 2: " << config.systemSetting2 << std::endl;
return 0;
}





这个代码实现的是 单例模式(Singleton Pattern),它的目的是确保在程序中只有一个 TaskManager 实例存在,并提供一个全局访问点来获取这个实例。

  • 单例模式 是一种设计模式,它通过控制实例的创建,确保类只有一个实例,并提供一个访问该实例的全局入口。
  • 在这个代码中,TaskManager 类就是一个单例类,它通过私有化构造函数和静态成员变量来确保只有一个 TaskManager 对象被创建。
static TaskManager* instance = nullptr;
  • instance 是一个静态成员变量,它保存了 TaskManager 类的唯一实例。
  • 静态变量意味着它在所有的类实例中是共享的,因此它不会随对象的创建而改变。
  • 初始值是 nullptr,表示还没有创建实例。
TaskManager() {}
  • 构造函数是私有的,意味着外部代码不能直接调用 TaskManager 的构造函数来创建实例。这样做是为了确保 TaskManager 类不能直接创建多个实例,只能通过 getInstance() 来获取实例。
static TaskManager* getInstance() {
if (instance == nullptr) {
instance = new TaskManager();
}
return instance;
}
  • getInstance() 是一个静态方法,它提供了访问单例对象的全局入口。
  • 懒汉式(Lazy initialization):在第一次调用 getInstance() 方法时,检查 instance 是否为 nullptr。如果是 nullptr,表示还没有创建实例,这时就创建一个新的 TaskManager 实例,并将其赋值给 instance。
  • 如果 instance 已经被创建过了,直接返回该实例。这样就保证了每次调用 getInstance() 都是返回同一个实例。

4. TaskManager::instance = nullptr;

跳转到“4. TaskManager::instance = nullptr;”
TaskManager* TaskManager::instance = nullptr;
  • 这行代码在类外部初始化静态成员变量 instance。它设置初始值为 nullptr,表示没有实例化任何 TaskManager 对象。
  • 这是必须的,因为静态成员变量在声明时不能初始化,必须在类外部进行初始化。
  • 私有构造函数:通过将构造函数设为私有,阻止了外部代码直接创建 TaskManager 的实例。
  • 静态成员变量:instance 静态成员变量保证了 TaskManager 类只有一个实例。在 getInstance() 方法中,如果 instance 为空,则创建实例并赋值给 instance。如果已经有了实例,直接返回这个实例。
  • 全局访问入口:通过 getInstance() 提供一个唯一的入口来访问单例对象,不需要手动创建新的实例。

你可以通过 TaskManager::getInstance() 来访问唯一的 TaskManager 实例。即使在程序中多次调用 getInstance(),也只会返回同一个 TaskManager 实例。

int main() {
// 获取唯一的 TaskManager 实例
TaskManager* manager1 = TaskManager::getInstance();
// 获取相同的实例
TaskManager* manager2 = TaskManager::getInstance();
// manager1 和 manager2 指向同一个实例
if (manager1 == manager2) {
qDebug() << "Both are the same instance!";
}
return 0;
}
  1. 私有构造函数:禁止外部直接创建 TaskManager 的实例。
  2. 静态成员变量:instance 保证了类中只有一个实例。
  3. getInstance() 方法:通过懒加载(延迟创建),第一次调用时创建唯一实例,后续的调用返回同一个实例。

这样就保证了 TaskManager 在整个程序运行过程中只有一个实例存在,所有需要访问 TaskManager 的地方都可以通过 getInstance() 获取到这个唯一实例。


单例模式是一种常见的设计模式,用于确保一个类只有一个实例,并提供一个全局访问点。在 C++ 中,单例模式通常有多种实现方式,但最常见和推荐的方式是使用 懒汉式单例模式,结合静态局部变量或静态成员变量来实现线程安全。

以下是几种常见的单例模式实现方式:

1. 懒汉式单例模式(推荐)

跳转到“1. 懒汉式单例模式(推荐)”

懒汉式单例模式在第一次使用时才创建实例,这种方式可以延迟实例的创建,节省资源。结合 C++11 的线程安全特性,可以实现简洁且高效的单例模式。

#include <mutex>
class Singleton
{
public:
// 获取单例实例
static Singleton* getInstance()
{
static Singleton instance; // 局部静态变量,线程安全
return &instance;
}
// 禁止拷贝和赋值
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
private:
// 私有构造函数
Singleton() {}
};
  • 线程安全:C++11 标准保证了局部静态变量的初始化是线程安全的。
  • 延迟初始化:实例只在第一次调用 getInstance() 时创建。
  • 简洁高效:代码简洁,且无需手动管理锁。

饿汉式单例模式在程序启动时就创建实例,这种方式简单直接,但无法延迟初始化。

class Singleton
{
public:
// 获取单例实例
static Singleton* getInstance()
{
return &instance;
}
// 禁止拷贝和赋值
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
private:
// 私有构造函数
Singleton() {}
// 静态实例
static Singleton instance;
};
// 在源文件中定义静态实例
Singleton Singleton::instance;
  • 简单直接:实现简单,易于理解。
  • 线程安全:实例在程序启动时创建,不存在线程安全问题。
  • 无法延迟初始化:实例在程序启动时就创建,可能会浪费资源。

3. 双重检查锁定(Double-Checked Locking)

跳转到“3. 双重检查锁定(Double-Checked Locking)”

双重检查锁定是一种优化的懒汉式单例模式,通过减少锁的使用次数来提高性能。但这种方法在 C++ 中需要特别小心,因为涉及到内存序问题。

#include <mutex>
#include <atomic>
class Singleton
{
public:
// 获取单例实例
static Singleton* getInstance()
{
if (!instance.load(std::memory_order_acquire)) // 第一次检查
{
std::lock_guard<std::mutex> lock(mutex);
if (!instance.load(std::memory_order_acquire)) // 第二次检查
{
instance.store(new Singleton(), std::memory_order_release);
}
}
return instance.load(std::memory_order_acquire);
}
// 禁止拷贝和赋值
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
private:
// 私有构造函数
Singleton() {}
// 静态成员变量
static std::atomic<Singleton*> instance;
static std::mutex mutex;
};
// 在源文件中定义静态成员变量
std::atomic<Singleton*> Singleton::instance(nullptr);
std::mutex Singleton::mutex;
  • 延迟初始化:实例只在第一次调用 getInstance() 时创建。
  • 高性能:通过减少锁的使用次数,提高了性能。
  • 复杂性:实现复杂,需要处理内存序问题。
  • 依赖于 C++11:需要使用 std::atomic 和 std::mutex,依赖于 C++11 标准。

4. 基于静态局部变量的单例模式(推荐)

跳转到“4. 基于静态局部变量的单例模式(推荐)”

这是懒汉式单例模式的一种变体,使用静态局部变量来实现线程安全。这种方式在 C++11 中是线程安全的,且代码简洁。

#include <mutex>
class Singleton
{
public:
// 获取单例实例
static Singleton* getInstance()
{
static Singleton instance; // 局部静态变量,线程安全
return &instance;
}
// 禁止拷贝和赋值
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
private:
// 私有构造函数
Singleton() {}
};
  • 线程安全:C++11 标准保证了局部静态变量的初始化是线程安全的。
  • 延迟初始化:实例只在第一次调用 getInstance() 时创建。
  • 简洁高效:代码简洁,且无需手动管理锁。

对于大多数现代 C++ 项目,推荐使用 基于静态局部变量的单例模式。这种实现方式简单、高效且线程安全,符合 C++11 标准。

#include <mutex>
class Singleton
{
public:
static Singleton* getInstance()
{
static Singleton instance; // 局部静态变量,线程安全
return &instance;
}
// 禁止拷贝和赋值
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
private:
// 私有构造函数
Singleton() {}
};

这种实现方式在大多数情况下都能满足需求,且无需担心线程安全问题。


另一种单例创建示例: 好的!以下是一个完整的代码示例,展示如何使用 Singleton 模板类和相关宏来实现一个单例类。我们将创建一个名为 MyClass 的单例类,并在主程序中使用它。

这是你提供的单例模板类的实现:

#ifndef SINGLETON_H
#define SINGLETON_H
#include <QMutex>
template <typename T>
class Singleton
{
public:
static T* getInstance();
private:
Q_DISABLE_COPY(Singleton)
};
template <typename T>
T* Singleton<T>::getInstance()
{
static QMutex mutex;
QMutexLocker locker(&mutex);
static T* instance = nullptr;
if (instance == nullptr)
{
instance = new T();
}
return instance;
}
#define Q_SINGLETON_CREATE(Class) \
private: \
friend class Singleton<Class>; \
\
public: \
static Class* getInstance() \
{ \
return Singleton<Class>::getInstance(); \
}
#define Q_SINGLETON_CREATE_H(Class) \
private: \
static Class* _instance; \
\
public: \
static Class* getInstance();
#define Q_SINGLETON_CREATE_CPP(Class) \
Class* Class::_instance = nullptr; \
Class* Class::getInstance() \
{ \
static QMutex mutex; \
QMutexLocker locker(&mutex); \
if (_instance == nullptr) \
{ \
_instance = new Class(); \
} \
return _instance; \
}
#endif // SINGLETON_H

2. 单例类的头文件:MyClass.h

跳转到“2. 单例类的头文件:MyClass.h”
#ifndef MYCLASS_H
#define MYCLASS_H
#include "Singleton.h"
class MyClass
{
Q_SINGLETON_CREATE_H(MyClass)
public:
void doSomething();
};
#endif // MYCLASS_H

3. 单例类的源文件:MyClass.cpp

跳转到“3. 单例类的源文件:MyClass.cpp”
#include "MyClass.h"
#include <iostream>
// 定义单例类的静态成员和方法
Q_SINGLETON_CREATE_CPP(MyClass)
void MyClass::doSomething()
{
std::cout << "MyClass::doSomething() called" << std::endl;
}
#include "MyClass.h"
int main()
{
// 获取单例实例
MyClass* instance1 = MyClass::getInstance();
MyClass* instance2 = MyClass::getInstance();
// 调用方法
instance1->doSomething();
instance2->doSomething();
// 检查是否是同一个实例
if (instance1 == instance2)
{
std::cout << "Both instances are the same!" << std::endl;
}
else
{
std::cout << "Instances are different!" << std::endl;
}
return 0;
}

假设你使用的是 Qt 和 C++,可以使用以下命令进行编译(假设你已经安装了 Qt 和 CMake):

cmake_minimum_required(VERSION 3.10)
project(SingletonExample)
set(CMAKE_CXX_STANDARD 11)
find_package(Qt5 REQUIRED COMPONENTS Core)
add_executable(SingletonExample main.cpp MyClass.cpp)
target_link_libraries(SingletonExample Qt5::Core)
终端窗口
mkdir build
cd build
cmake ..
make
./SingletonExample

运行程序后,输出如下:

MyClass::doSomething() called
MyClass::doSomething() called
Both instances are the same!
  • 单例模式:
    • MyClass 是一个单例类,通过 Q_SINGLETON_CREATE_H 和 Q_SINGLETON_CREATE_CPP 宏定义,确保了全局只有一个实例。
    • getInstance() 方法返回同一个实例,即使多次调用,返回的也是同一个对象。
  • 线程安全:
    • 使用了 QMutex 和 QMutexLocker,确保在多线程环境下实例化是线程安全的。
  • 延迟初始化:
    • 单例实例在第一次调用 getInstance() 时被创建,之后每次调用都返回同一个实例。

希望这个完整的示例能帮助你更好地理解和使用单例模式!



来源:CSDN 原文,首次发布于 2025-03-26。