2

单例模式 - Hosseini

 2 weeks ago
source link: https://www.cnblogs.com/hosseini/p/18146328
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

单例模式

Posted on 2024-04-19 16:45  Hosseini  阅读(128)  评论(0)  编辑  收藏  举报

单例模式的写法总的来说分为两类:饿汉式和饱汉式,他们都依赖C++的一个知识点:static的使用。

具体的写法有很多种,首先给出最推荐的写法。这个写法是所谓的饱汉式(即:延时初始化,再使用的时候才去初始化)

class Singleton
{
public:
    static Singleton& getInstance() {
        static Singleton _instance;
        return _instance;
    }
    Singleton(const Singleton& other) = delete;
    Singleton(Singleton&& other) = delete;
    Singleton& operator=(const Singleton& other) = delete;
    Singleton&operator=(Singleton&& other) = delete;
    
private:
    Singleton() = default;
    ~Singleton() = default;
};

也看到过有人这样写,我觉得没有必要。

class Singleton
{
public:
    static Singleton* getInstance() {
        static Singleton _instance;
        return &_instance;
    }
    Singleton(const Singleton& other) = delete;
    Singleton(Singleton&& other) = delete;
    Singleton& operator=(const Singleton& other) = delete;
    Singleton&operator=(Singleton&& other) = delete;
    
private:
    Singleton() = default;
    ~Singleton() = default;
};

下面给出其他的写法

写法一:静态成员饿汉式

存在的问题:no local static(函数外的static)变量在不同的编译单元中的初始化顺序未定义,即static Singleton& getInstance()和static Singleton _instance的顺序未知。

class Singleton
{
public:
    static Singleton& getInstance() {
        return _instance;
    }
    Singleton(const Singleton& other) = delete;
    Singleton(Singleton&& other) = delete;
    Singleton& operator=(const Singleton& other) = delete;
    Singleton& operator=(Singleton&& other) = delete;

private:
    static Singleton _instance;
    Singleton() = default;
    ~Singleton() = default;
};
Singleton Singleton::_instance;

写法二:指针饱汉式

存在的问题:1.不是线程安全(改进:加锁)、2.内存泄漏(改进:使用智能指针或者依赖静态的嵌套类的析构函数)

class Singleton
{
public:
    static Singleton* getInstance() {
        if (_instance)
            _instance = new Singleton();
        return _instance;
    }
    Singleton(const Singleton& other) = delete;
    Singleton(Singleton&& other) = delete;
    Singleton& operator=(const Singleton& other) = delete;
    Singleton& operator=(Singleton&& other) = delete;

private:
    static Singleton *_instance;
    Singleton() = default;
    ~Singleton() = default;
};
Singleton* Singleton::_instance = nullptr;

题外话:

写法二中的指针到底需不需要释放?

如果对象没有被释放,在程序运行期间可能会存在内存泄露问题。

有人可能会说,在程序结束时,操作系统会进行必要的清理工作,包括释放进程的所有堆栈等信息,即使存在内存泄露,操作系统也会收回的;且对于单例来讲,进程运行期间仅有一个,对于现代计算机而言,占用的内存貌似也不会太大。而且该实例有可能根本就没有进行内存的申请操作,这种情况下不释放实例所占内存,对进程的运行也不会造成影响。

但我觉得还是要在合适的地方加上释放(在哪儿合适呢,在程序关闭前?),养成良好的习惯,并且对于大型项目来说,会有内存检测工具,避免报内存泄漏,增加检查成本。

 当然,如果采用前面的最佳模式,就无需考虑这个问题了,只需要写好这个类的析构函数就可以了。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK