【c++八股】手撕单例模式

懒汉模式#

class Singleton {
public:
    static Singleton& Instance() {
        if(instance_ == nullptr)
            instance_ = new Singleton();
        }
        return instance_;
    }

private:
    Singleton() {}
    ~Singleton() {}
	// 防拷贝
	Singleton(const Singleton& sing) = delete;
    Singleton& operator=(const Singleton& sing) = delete;
	
	static Singleton* instance_;
};
Singleton* Singleton::instance_ = nullptr;

懒汉模式-线程安全加锁#

假如多个线程都调用了Instance方法,且都走到了判断为空那一步,可能同时成立。这样会导致多个线程同时创建instance_对象,即创建了多次,出现线程不安全的情况

使用lock_guard和mutex进行加锁:

class Singleton {
public:
    static Singleton* Instance() {
        //不需要每次都进来获取锁资源,提高效率
        if(instance_ == nullptr) {
            lock_guard<mutex> lk(mutex_);
            if(instance_ == nullptr) {
                instance_ = new Singleton();
            }
        }
        return instance_;
    }
    
private:
    Singleton() {}
    ~Singleton() {}
    Singleton(const Singleton& sing) = delete;
    Singleton& operator=(const Singleton& sing) = delete;
    static Singleton* instance_;
    static mutex mutex_;
};
Singleton* Singleton::instance_ = nullptr;
mutex Singleton::mutex_;

懒汉模式-内存泄漏优化#

单例类中new出来的实例没有得到释放,所以需要方法来delete这个对象。

解决方法:(1)智能指针(2)嵌套类(3)C++11的静态对象特性

1 智能指针#

利用shared_ptr的特性。

class Singleton {
public:
    static boost::shared_ptr<Singleton> Instance() {
        if(instance_ == nullptr) {
            lock_guard<mutex> lk(mutex_);
            if(instance_ == nullptr) {
                // 替换托管对象,并设置智能指针引用计数为0后的delete方法
                instance_.reset(new Singleton(), destroyInstance);
            }
        }
        return instance_;
    }
    static void destroyInstance(Singleton* instance) {
        delete instance;
    }
    
private:
    Singleton() {}
    ~Singleton() {}
    Singleton(const Singleton& sing) = delete;
    Singleton& operator=(const Singleton& sing) = delete;
    static boost::shared_ptr<Singleton> instance_;
    static mutex mutex_;

};
boost::shared_ptr<Singleton> Singleton::instance_ = nullptr;
mutex Singleton::mutex_;

2 嵌套类#

在单例类中内嵌一个类,并初始化一个静态对象。当程序结束的时候,该对象进到析构的同时,将单例实例删除。这样就能回收单例实例的资源。

class Singleton {
public:
    static Singleton* Instance() {
        if(instance_ == nullptr) {
            lock_guard<mutex> lk(mutex_);
            if(instance == nullptr) {
                instance_ = new Singleton();
            }
        }
        return instance_;
    }
private:
    Singleton() {}
    ~Singleton() {}
    Singleton(const Singleton& sing) = delete;
    Singleton& operator=(const Singleton& sing) = delete;
    static Deletor deletor_;
    static Singleton* instance_;
    static mutex mutex_;
    
    class Deletor {
    public:
        Deletor() {}
        ~Deletor() {
            if(instance_ != nullptr) {
                delete instance_;
                instance_ = nullptr;
            }
        }
    }
};
Singleton::Deletor Singleton::deletor_;
Singleton* Singleton::instance_ = nullptr;
mutex Singleton::mutex_;

3 C++11的静态对象特性#

C++11标准规定局部的静态对象在多线程场景下,只有初次访问才会被创建实例,后续都是直接获取。若未创建成功,其他线程就会等待,不会出现竞争的情况。而且资源会自动被销毁释放。

class Singleton {
public:
    static Singleton* Instance() {
        static Singleton* instance_;
        return instance_;
    }
private:
    Singleton() {}
    ~Singleton() {}
    Singleton(const Singleton& sing) = delete;
    Singleton* operator=(const Singleton& sing) = delete;
};

饿汉模式#

程序启动阶段会初始化类的静态变量。

优点是不会有线程安全问题,缺点是浪费内存。

static对象在不同编译单元中的初始化顺序是未定义的。如果在初始化完成之前调用 Instance() 方法会返回一个未定义的实例。

class Singleton {
public:
    // 对外提供获取实例的静态方法
    static Singleton* Instance() {
        return instance_;
    }
private:
    // 私有构造函数
    Singleton() {}
    // 防拷贝
    Singleton(const Singleton& sing) = delete;
    Singleton& operator=(const Singleton& sing) = delete;
    
    static Singleton* instance_;
};

Singleton* Singleton::instance_ = new Singleton();

参考#

https://blog.csdn.net/db_linux_driver/article/details/132548669

posted @   rthete  阅读(119)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
主题色彩
点击右上角即可分享
微信分享提示