[C++ study notes] 12. Detailed explanation of singleton mode

1 singleton mode

In C++, the singleton pattern is a common design pattern used to ensure that a class has only one instance and provide a global access point. Common C++ singleton patterns include the following:

  1. Hungry-style singleton mode: Create a singleton instance when the program starts to ensure thread safety and performance. In this mode, the getInstance() method directly returns the initialized singleton instance.
  2. Lazy singleton mode: Create a singleton instance at the first request to save resources. A simple implementation can be used in a single-threaded environment, but thread safety issues need to be considered in a multi-threaded environment.
  3. Double-Checked Locking/Double-Checked Locking (Double-Checked Locking) singleton mode: combines the advantages of the lazy and hungry singleton mode, that is, checks whether the instance exists at the first request, and locks it if it does not exist Synchronize and check whether the instance exists again before locking to avoid unnecessary locking operations.
  4. Internal static variable singleton mode: define a private static member variable as an instance, and at the same time declare the constructor as private to avoid direct creation of objects externally. When an instance needs to be obtained, return the reference of the static variable through the static member function to ensure global uniqueness.
  5. Registration singleton mode: Register each singleton instance to the singleton manager, and obtain the instance by name or index. When a new instance needs to be created, first check whether the instance already exists in the registry, if not, create one and add it to the registry.

The above are several implementations of the common C++ singleton pattern. Choosing the right singleton pattern depends on the specific application scenarios and requirements.

Here is sample code for each of the different C++ singleton patterns:

2 Hungry Chinese singleton mode:

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;
}

In this sample code, the instance of the Singleton class is statically initialized as a constant, which means that it already exists when the program starts, so the getInstance() method can directly return the instance. This approach can guarantee thread safety and performance.

3 Lazy singleton mode:

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;
}

In this sample code, an instance of the Singleton class is created on the first request, which saves resources. Since thread safety is not considered, there may be problems in a multi-threaded environment.

4 Double-Checked Locking/Double-Checked Locking (Double-Checked Locking) singleton mode:

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;
}

In this sample code, the Singleton class uses a double-checked lock to ensure that there is only one instance, and uses a static mutex to ensure thread safety. On the first request, only one thread can enter the critical section and create an instance.

5 Internal static variable singleton mode:

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;
}

In the sample code, the instance of the Singleton class is defined as a static local variable, which means it will only be initialized on the first use and is thread-safe.

6 Registry singleton mode

The registered singleton mode refers to registering the Singleton object in a global object manager when the program starts, and obtaining the Singleton object through the manager. The specific implementation is as follows:

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_;
};


The advantage of this method is that singleton objects can be added or deleted dynamically, but the disadvantage is that it is more complicated to implement than other methods.

Guess you like

Origin blog.csdn.net/qq_38753749/article/details/129913812