【C++学习笔记】十二、单例模式详解

1 单例模式

在C++中,单例模式是一种常用的设计模式,用于确保一个类只有一个实例,并提供全局访问点。常见的C++单例模式包括以下几种:

  1. 饿汉式单例模式:在程序启动时就创建单例实例,以保证线程安全和性能。在该模式下,getInstance()方法直接返回已经初始化好的单例实例。
  2. 懒汉式单例模式:在第一次请求时才创建单例实例,以节省资源。在单线程环境下可以使用简单的实现方式,但在多线程环境下需要考虑线程安全问题。
  3. 双检锁/双重校验锁(Double-Checked Locking)单例模式:结合了懒汉式和饿汉式单例模式的优点,即在第一次请求时检查实例是否存在,如果不存在则加锁进行同步,在加锁之前再次检查实例是否存在,以避免不必要的加锁操作。
  4. 内部静态变量单例模式:定义一个私有的静态成员变量作为实例,同时将构造函数声明为私有,避免外部直接创建对象,当需要获取实例时,通过静态成员函数返回该静态变量的引用,以保证全局唯一性。
  5. 注册表单例模式:将每个单例实例注册到单例管理器中,通过名称或者索引来获取实例。当需要创建新的实例时,先在注册表中查找是否已经存在该实例,如果不存在则创建一个并添加到注册表中。

以上是常见的C++单例模式的几种实现方式。选择合适的单例模式取决于具体的应用场景和需求。

以下是每种不同的C++单例模式的示例代码:

2 饿汉式单例模式:

class Singleton {
private:
    static Singleton* instance; // 实例指针

    // 私有化构造函数和拷贝构造函数,以防止外部创建或复制实例
    Singleton() {}
    Singleton(const Singleton&) {}

public:
    static Singleton* getInstance() {
        return instance;
    }

    void doSomething() { /* 单例类的具体实现 */ }
};

Singleton* Singleton::instance = new Singleton(); // 静态初始化实例

int main() {
    Singleton* singleton = Singleton::getInstance(); // 获取单例实例
  
    return 0;
}

在该示例代码中,Singleton类的实例被静态初始化为一个常量,这意味着它在程序启动时就已经存在,因此getInstance()方法可以直接返回该实例。这种方式可以保证线程安全和性能。

3 懒汉式单例模式:

class Singleton {
private:
    static Singleton* instance; // 实例指针

    // 私有化构造函数和拷贝构造函数,以防止外部创建或复制实例
    Singleton() {}
    Singleton(const Singleton&) {}

public:
    static Singleton* getInstance() {
        if (instance == nullptr) { // 如果没有实例,则创建一个新实例
            instance = new Singleton();
        }
        return instance;
    }

    void doSomething() { /* 单例类的具体实现 */ }
};

Singleton* Singleton::instance = nullptr;

int main() {
    Singleton* singleton = Singleton::getInstance(); // 获取单例实例
  
    return 0;
}

在该示例代码中,Singleton类的实例在第一次请求时被创建,这样可以节省资源。由于没有考虑线程安全问题,因此在多线程环境下可能存在问题。

4 双检锁/双重校验锁(Double-Checked Locking)单例模式:

class Singleton {
private:
    static Singleton* instance; // 实例指针

    // 私有化构造函数和拷贝构造函数,以防止外部创建或复制实例
    Singleton() {}
    Singleton(const Singleton&) {}

public:
    static Singleton* getInstance() {
        if (instance == nullptr) { // 如果没有实例,则加锁创建一个新实例
            std::lock_guard<std::mutex> lock(mutex); // 加锁
            if (instance == nullptr) { // 再次检查实例是否为空
                instance = new Singleton();
            }
        }
        return instance;
    }

    void doSomething() { /* 单例类的具体实现 */ }

    static std::mutex mutex; // 静态互斥量,用于线程同步
};

Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mutex;

int main() {
    Singleton* singleton = Singleton::getInstance(); // 获取单例实例
  
    return 0;
}

在该示例代码中,Singleton类使用了双检锁来确保只有一个实例,并使用了静态互斥量来保证线程安全。在第一次请求时,只有一个线程可以进入临界区并创建实例。

5 内部静态变量单例模式:

class Singleton {
private:
    // 私有化构造函数和拷贝构造函数,以防止外部创建或复制实例
    Singleton() {}
    Singleton(const Singleton&) {}

public:
    static Singleton& getInstance() {
        static Singleton instance; // 静态局部变量,只会初始化一次
        return instance;
    }

    void doSomething() { /* 单例类的具体实现 */ }
};

int main() {
    Singleton& singleton = Singleton::getInstance(); // 获取单例实例
  
    return 0;
}

在该示例代码中,Singleton类的实例被定义为静态局部变量,这意味着它只会在第一次使用时进行初始化,并且是线程安全的。

6 登记式单例模式

登记式单例模式是指在程序启动时将Singleton对象注册到一个全局的对象管理器中,通过该管理器获取Singleton 对象。具体实现如下:

class Singleton {
public:
    static Singleton& getInstance() {
        if (instance == nullptr) {
            instance = new Singleton();
            SingletonManager::getInstance().registerObject("Singleton", instance);
        }
        return *instance;
    }
private:
    static Singleton* instance;
    Singleton() {}
    ~Singleton() {}
};

Singleton* Singleton::instance = nullptr;

// 对象管理器
class SingletonManager {
public:
    static SingletonManager& getInstance() {
        static SingletonManager instance;
        return instance;
    }
    void registerObject(const std::string& name, Singleton* object) {
        objects_[name] = object;
    }
    Singleton* getObject(const std::string& name) {
        if (objects_.find(name) != objects_.end()) {
            return objects_[name];
        } else {
            return nullptr;
        }
    }
private:
    std::unordered_map<std::string, Singleton*> objects_;
};


该方式的优点是可以动态添加或删除单例对象,缺点是相对于其他方式而言实现起来比较复杂。

你可能感兴趣的:(C++学习笔记,单例模式,c++,学习)