物是人非事事休,欲语泪先流|

游客0721

园龄:2年粉丝:4关注:2

单例模式(正式)

当需要严格控制一个类在全局只有唯一一个实例,并且可以随时调用它的时候,就可以使用单例模式。

单例模式可以以实例化时间分为懒汉式和饿汉式、以C实现方式分为C++98的实现以及C++11的实现。

懒汉式

c++11
class Singleton {
public:
static Singleton* getInstance() {
if(m_instance == nullptr) {
m_instance = new Singleton();
}
return m_instance;
}
private:
Singleton(){}
~Singleton(){}
static Signeton* m_instance;
};
class Singleton {
public:
static Singleton& GetInstance() {
static Singleton instance;
return instance;
}
private:
Singleton() = default;
~Singleton() {}
};

也就是说, Singleton 通过将构造函数私有化实现了对实例化的控制,只有通过调用 getInstance() 才能生成并获得这唯一一个实例。

同时,这是一个懒汉式的实现,只有在调用 getInstance() 一次过后才有一个 Singleton 被实例化。

代码注解:

  • 这段代码使用指针的目的是为了延迟单例类的实例化,并在需要时动态地创建和访问实例对象。

  • 通过使用 new 运算符创建一个 Singleton 类的实例对象,并将其赋值给静态成员 m_instance,以确保只有一个实例对象被创建。需要注意的是,静态成员 m_instance 存储的是实例对象的地址,而不是对象本身。因此,在使用时需要通过解引用操作符 * 来获取实际的对象。

静态成员变量定义只能在源文件:

重复编译 减少初始化操作

静态成员:

  • 如果把类的成员声明为静态的,就可以把它与类的对象独立开来(静态成员不属于对象)

  • 用 static 关键字把类的成员变量声明为静态,表示它在程序中(不仅是对象)是共享的。

  • 静态成员只有一份,在全局存储区

  • 静态成员使用类名加范围解析运算符 :: 就可以访问,不需要创建对象。

饿汉式

// in 'Singleton.h'
class Singleton {
public:
static Singleton& GetInstance {
return instance;
}
private:
Singleton() = default;
~Singleton() {}
static Singleton instance;
};
// in 'Singleton.cpp'
Singleton Singleton::instance;

代码讲解

  • GetInstance() 方法返回一个 Singleton 对象的引用。

  • 在 C++11 中,使用局部静态变量可以确保只有一个实例对象被创建。在这段代码中,instance 是一个局部静态变量,它在第一次调用 GetInstance() 方法时被创建,而在后续的调用中会直接返回已经存在的实例对象。

  • 构造函数 Singleton() 和析构函数 ~Singleton() 都使用 default 关键字进行了默认定义,即使用编译器生成的默认实现。它们被声明为 private,防止在类外部直接创建和销毁对象。

  • 通过这种实现方式,可以简洁地实现只有一个实例对象被创建,并且可以通过引用来访问该对象。

懒汉模式和恶汉模式是两种单例模式实现方式的区别:

懒汉模式:在首次使用时才创建实例对象,延迟实例化,可能存在线程安全问题。

恶汉模式:在类加载时就创建实例对象,立即实例化,不存在线程安全问题。

懒汉模式节省内存空间,但可能引入延迟和线程安全问题;恶汉模式简单直接,但可能浪费部分内存空间。选择取决于内存占用、延迟和线程安全需求。

竞争的场景:

两个线程在调用结构的过程中,如判断是否空指针的时候,一个在判断为空指针后准备创建对象,另一个在此时也判断为空的指针
//Singleton.h
/* C++98 */
class Singleton11{
public:
static Singleton98* getInstance() {
if(m_instance == nullptr) {
std::lock_guard<std::mutex> lock(m_mutex);
if(m_instance == nullptr) {
m_instance = new Singleton();
}
}
return m_instance;
}
private:
//...
}
/* C++11 */
class Singleton11{
public:
static Singleton11& getInstance() {
std::call_once(m_flag, []() {
m_instance.reset(new Singleton11);
});
}
private:
//...
static std::mutex m_mutex;
}
//Singleton.cpp
/* C++98 */
Singleton98* Singleton98::m_instance = nullptr;
std::mutex Singleton98::m_mutex;
/* C++11 */
std::unique_ptr<Singleton11> Singleton11::m_instance;
std::once_flag Singleton11::m_flag;

问题:image

  • 多线程需要考虑多次new的问题,需要使用线程同步如互斥锁

  • 忘记delete!

用处

资源共享:当多个对象需要共享同一个资源时,可以使用单例模式来管理该资源。例如,数据库连接池、线程池等。
配置信息:单例模式可以用于管理全局的配置信息,确保在整个应用程序中只有一个配置对象,方便访问和修改配置。
日志记录器:在日志记录中,使用单例模式可以确保只有一个日志记录器实例,所有的日志信息都在同一个地方进行记录,并且可以方便地访问和控制日志记录器。

本文作者:Gal0721

本文链接:https://www.cnblogs.com/Gal0721/p/17726168.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   游客0721  阅读(9)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起
  1. 1 優しい光 水谷広実
  2. 2 ひだまりの中で SONO MAKERS,鈴丸
  3. 3 白い吐息 MANYO
  4. 4 夏の子守歌 折戸伸治
ひだまりの中で - SONO MAKERS,鈴丸
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.