「生活可以更简单, 欢迎来到我的开源世界」
  1. 只适用于单线程模式
  2. 线程安全、内存安全的单例模式
  3. 使用局部静态变量实现的单例模式
  4. 参考
面试题2:实现Singleton模式
2020-07-09
」 「

剑指offer面试题2,实现单例模式。

题目:设计一个类,我们只能生成该类的一个实例。

只适用于单线程模式

#include <iostream>
using std::cout;
using std::endl;

class Singleton{
private:
Singleton(){
cout << "constructor called" << end;
}
Singleton(Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
static Singleton* ptr;
public:
~Singleton(){
cout << "destructor called!"<< endl;
}
static Singleton* get_instance(){
if(ptr == nullptr){
ptr = new Singleton;
}
return ptr;
}
};
Singleton* Singleton::ptr = nullptr;

int main(){
Singleton* instance = Singleton::get_instance();
Singleton* instance_2 = Singleton::get_instance();
return 0;
}

运行结果是:(只有一次类的构造函数被调用)

constructor called!

存在问题:

线程安全、内存安全的单例模式

#include <iostream>
#include <memory> // shared_ptr
#include <mutex> // mutex

class Singleton{
public:
typedef std::shared_ptr<Singleton> Ptr;
~Singleton(){
std::cout<<"destructor called!"<<std::endl;
}
Singleton(Singleton&)=delete;
Singleton& operator=(const Singleton&)=delete;
static Ptr get_instance(){
// "double checked lock"
if(m_instance_ptr==nullptr){
std::lock_guard<std::mutex> lk(m_mutex);
if(m_instance_ptr == nullptr){
m_instance_ptr = std::shared_ptr<Singleton>(new Singleton);
}
}
return m_instance_ptr;
}


private:
Singleton(){
std::cout<<"constructor called!"<<std::endl;
}
static Ptr m_instance_ptr;
static std::mutex m_mutex;
};

// initialization static variables out of class
Singleton::Ptr Singleton::m_instance_ptr = nullptr;
std::mutex Singleton::m_mutex;

int main(){
Singleton::Ptr instance = Singleton::get_instance();
Singleton::Ptr instance2 = Singleton::get_instance();
return 0;
}

运行结果如下,发现确实只构造了一次实例,并且发生了析构。

constructor called!
destructor called!

这种方法的优点是

不足之处在于: 、

使用局部静态变量实现的单例模式

#include <iostream>

class Singleton
{
public:
~Singleton(){
std::cout<<"destructor called!"<<std::endl;
}
Singleton(const Singleton&)=delete;
Singleton& operator=(const Singleton&)=delete;
static Singleton& get_instance(){
static Singleton instance;
return instance;

}
private:
Singleton(){
std::cout<<"constructor called!"<<std::endl;
}
};

int main(int argc, char *argv[])
{
Singleton& instance_1 = Singleton::get_instance();
Singleton& instance_2 = Singleton::get_instance();
return 0;
}

这是最推荐的一种单例实现方式:

  1. 通过局部静态变量的特性保证了线程安全 (C++11, GCC > 4.3, VS2015支持该特性);
  2. 不需要使用共享指针,代码简洁;
  3. 注意在使用的时候需要声明单例的引用 Single& 才能获取对象。

另外网上有人的实现返回指针而不是返回引用

static Singleton* get_instance(){
static Singleton instance;
return &instance;
}

这样做并不好,理由主要是无法避免用户使用delete instance导致对象被提前销毁。还是建议大家使用返回引用的方式。

参考

C++ 单例模式总结与剖析

<⇧>