C++ 单例模式

引言

前段时间面试时遇到一个问题,静态变量是否为线程安全的。静态变量在编译时进入main()函数前便进行初始化,其生命周期伴随着整个程序的生命周期,在程序结束时才会释放内存。对于静态实例变量,其在构造的时候是线程安全的,构造过程中第一个线程执行构造,其他线程会阻塞在构造的过程,然后构造完毕后该对象内部的静态变量是非线程安全的,因为其共享的是一份内存。

因此,在设计工具类的时候,对于没有使用静态变量的静态工具类方法,是不需要加锁的。在使用单例模式做工具类的时候,静态方法需要被加锁,这是因为所有的线程虽然有自己的方法栈,但是在方法栈中操作的是同一个对象的实体,需要进行加锁同步。

单例模式

现在回想起来,其实面试官真正想问的问题是如何设计一个单例模式类。

单例模式是指确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。

单例模式常用于系统的日志输出等工具类的实现。其特点如下:

优点:仅有一个实例,减少内存开销;避免对一个资源的多重占用;设置全局访问点,优化和贡献资源;

缺点:扩展性差;不利于测试;与单一职责原则有冲突,单例模式要把单例和业务逻辑融合在一个类中。

懒汉模式

懒汉模式是指只有在第一次用到类实例的时候才会去实例化。最普通的懒汉模式如下:

class Singleton
{
private:
	Singleton() {}
	static Singleton* m_instance;
public:
	static Singleton* getInstance();
};

Singleton* Singleton::m_instance = NULL;
Singleton* Singleton::getInstance()
{
	if (nullptr == m_instance)
	{
		m_instance = new Singleton();
	}
	return m_instance;
}

懒汉模式保证只有一个实例是通过第一次访问getInstance()这个函数时实现的,只有第一次访问时才会构建对象,否则仅返回相同实例的指针。但是其会存在两个问题:多个线程同时第一次访问getInstance时会同时构造一个实例给m_instance造成错误;new出来的东西没有进行析构,导致内存泄漏。

在C++11中,我们可以借助call_once和unique_ptr来实现线程安全的单例模式,此处搬运别人的代码如下:

class Singleton {
public:
  static Singleton& GetInstance() {
    static std::once_flag s_flag;
    std::call_once(s_flag, [&]() {
      m_instance.reset(new Singleton);
    });

    return *m_instance;
  }

  ~Singleton() = default;

private:
  Singleton() = default;// ctor hidden
  Singleton(const Singleton&) = delete;	// copy ctor hidden
  Singleton& operator=(const Singleton&) = delete; // assign op. hidden

private:
  static std::unique_ptr<Singleton> m_instance;
};

其中unique_ptr智能指针可禁止拷贝和赋值,由于智能指针的特性可以避免了内存泄漏,call_once函数可避免getInstance在第一次时多个线程同时访问时出现的同时构造的问题。

由此看来,C++11的一些特性太强大了,怪不得好几个面试官都要问C++11的问题呢。

饿汉模式

饿汉模式是指单例类定义的时候就进行实例化,饥不择食。实现代码如下:

class Singleton
{
private:
	Singleton() {}
	~Singleton()
	{
		if (nullptr != m_instance)
		{
			delete m_instance;
			m_instance = nullptr;
		}
	}
	static Singleton* m_instance;

public:
	static Singleton* getInstance();
};

Singleton* Singleton::m_instance = new Singleton();    //static members initialize out of class
Singleton* Singleton::getInstance()
{
	return m_instance;
}

 

参考链接:

https://blog.youkuaiyun.com/u011726005/article/details/82356538

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值