Loading

【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 @ 2024-03-06 15:47  rthete  阅读(94)  评论(0编辑  收藏  举报