单例模式(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对象被创建。
代码解析
跳转到“代码解析”1. 静态成员变量
跳转到“1. 静态成员变量”static TaskManager* instance = nullptr;instance是一个静态成员变量,它保存了TaskManager类的唯一实例。- 静态变量意味着它在所有的类实例中是共享的,因此它不会随对象的创建而改变。
- 初始值是
nullptr,表示还没有创建实例。
2. 私有构造函数
跳转到“2. 私有构造函数”TaskManager() {}- 构造函数是私有的,意味着外部代码不能直接调用
TaskManager的构造函数来创建实例。这样做是为了确保TaskManager类不能直接创建多个实例,只能通过getInstance()来获取实例。
3. getInstance() 静态方法
跳转到“3. 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;}总结
跳转到“总结”- 私有构造函数:禁止外部直接创建
TaskManager的实例。 - 静态成员变量:
instance保证了类中只有一个实例。 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()时创建。 - 简洁高效:代码简洁,且无需手动管理锁。
2. 饿汉式单例模式
跳转到“2. 饿汉式单例模式”饿汉式单例模式在程序启动时就创建实例,这种方式简单直接,但无法延迟初始化。
实现代码
跳转到“实现代码”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 的单例类,并在主程序中使用它。
1. 头文件:Singleton.h
跳转到“1. 头文件:Singleton.h”这是你提供的单例模板类的实现:
#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_H2. 单例类的头文件: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_H3. 单例类的源文件: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;}4. 主程序:main.cpp
跳转到“4. 主程序:main.cpp”#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;}5. 编译和运行
跳转到“5. 编译和运行”假设你使用的是 Qt 和 C++,可以使用以下命令进行编译(假设你已经安装了 Qt 和 CMake):
CMakeLists.txt
跳转到“CMakeLists.txt”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 buildcd buildcmake ..make./SingletonExample6. 运行结果
跳转到“6. 运行结果”运行程序后,输出如下:
MyClass::doSomething() calledMyClass::doSomething() calledBoth instances are the same!7. 解释
跳转到“7. 解释”- 单例模式:
MyClass是一个单例类,通过Q_SINGLETON_CREATE_H和Q_SINGLETON_CREATE_CPP宏定义,确保了全局只有一个实例。getInstance()方法返回同一个实例,即使多次调用,返回的也是同一个对象。
- 线程安全:
- 使用了
QMutex和QMutexLocker,确保在多线程环境下实例化是线程安全的。
- 使用了
- 延迟初始化:
- 单例实例在第一次调用
getInstance()时被创建,之后每次调用都返回同一个实例。
- 单例实例在第一次调用
希望这个完整的示例能帮助你更好地理解和使用单例模式!
来源:CSDN 原文,首次发布于 2025-03-26。