有效的单例类 ?
A valid singleton Class ?
class Singleton
{
private:
static Singleton s;
Singleton(){}
public:
static Singleton *getInstance()
{
return &s;
}
};
Singleton Singleton::s;
这是一个有效的单例类吗?
class Singleton
{
private:
static Singleton *m_instance;
Singleton(){}
public:
static Singleton *getInstance()
{
return m_instance;
}
};
Singleton * Singleton::m_instance = new Singleton;
.
class Singleton
{
private:
static Singleton *m_instance;
Singleton(){}
public:
static Singleton *getInstance()
{
if(m_instance == NULL)
{
lock();
if(m_instance == NULL)
m_instance = new Singleton;
unlock();
}
return m_instance;
}
};
Singleton * Singleton::m_instance = NULL;
上面的三个单例类都是线程安全的,但它们都容易出现"静态初始化顺序惨败",对吗?
这是一个有效的单例类吗?
现在,在编辑之后,答案是肯定的,它是有效的,它也是线程安全的,因为所有非函数范围的静态变量都是在main()
之前构造的,而只有一个活动线程。
C++ 标准 n3337 § 3.6.2/1 § 3.6.2/2:非局部变量的初始化
有两大类命名非局部变量:具有 静态存储持续时间 (3.7.1) 和线程存储持续时间 (3.7.2). 具有静态存储持续时间的非局部变量为 作为程序启动的结果进行初始化。非本地 具有线程存储持续时间的变量初始化为 线程执行的结果。在启动的每个阶段中,初始化按如下方式进行。
具有静态存储持续时间 (3.7.1) 或线程存储的变量 持续时间 (3.7.2) 应在任何其他之前初始化 (8.5) 为零 进行初始化。执行常量初始化:
— 如果每个完整表达式(包括隐式转换)都 出现在带有静态或线程的引用的初始值设定项中 存储持续时间是一个常量表达式 (5.19),引用为 绑定到指定具有静态存储持续时间的对象的 lvalue 或临时(见12.2);
— 如果初始化了具有静态或线程存储持续时间的对象 通过构造函数调用,如果构造函数是 constexpr 构造函数, 如果所有构造函数参数都是常量表达式(包括 转换),如果在函数调用替换 (7.1.5) 之后, MEM 初始值设定项中的每个构造函数调用和完整表达式,以及 在非静态数据成员的大括号或等于初始值设定项中,有一个 常量表达;
— 如果具有静态或线程存储持续时间的对象不是 由构造函数调用初始化,如果每个完整表达式 出现在其初始值设定项中的是一个常量表达式。
零初始化和常量初始化一起称为 静态初始化;所有其他初始化都是动态的 初始化。静态初始化应在任何之前执行 进行动态初始化。(...)
C++ 标准 n3337 § 6.7/4:声明声明
所有块范围变量的零初始化 (8.5) 与静态 存储持续时间 (3.7.1) 或线程存储持续时间 (3.7.2) 为 在进行任何其他初始化之前执行。不断 具有静态存储的块范围实体的初始化 (3.6.2) 持续时间(如果适用)在其块首先出现之前执行 进入。允许实现尽早执行 使用静态或线程初始化其他块范围变量 与实现相同的条件下的存储持续时间 允许使用 static 或线程静态初始化变量 命名空间范围内的存储持续时间。否则,这样的变量是 初始化控件第一次通过其声明时; 这样的变量在其完成时被视为初始化 初始化。如果初始化通过引发异常退出, 初始化未完成,因此下次将再次尝试 时间控制进入声明。如果控件输入声明 在初始化变量时并发 执行应等待初始化完成*)。(...)
*):
实现不得在执行 初始值设定项。
但它仍然容易出现静态初始化顺序惨败。编写getInstance
的常用方法是:
Singleton& getInstance()
{
static Singleton instance;
return instance;
}
这样就可以避免此初始化问题。
这是线程安全的单例类吗?
在 C++11 中,上面的代码是线程安全的。在 C++03 中,您可以使用
pthread_once
除此之外,您还应该防止复制和分配:
Singleton( Singleton const&); // Don't Implement
void operator=( Singleton const&); // Don't implement
据我所知,它是线程安全的。但它容易受到静态初始化顺序惨败的影响。
如果一个对象尝试访问其构造函数中的Singleton
,并且该对象是在程序初始化期间构造的,并且此代码位于Singleton
以外的另一个编译单元中,则它可能会也可能不会崩溃,因为Singleton::s
可能尚未初始化(因为跨编译单元的静态对象的初始化顺序未定义)。下面是一个示例:
// in another compilation unit, far far away
struct Foo {
Foo() {
Singleton::getInstance();
}
};
Foo foo;
这是懒惰的初始化单例,是的。它在 C++11 下是线程安全的。
- C++ 实现模板单例类时出现链接错误
- 具有非默认构造函数的单例类
- 单例类析构函数无法清理 (SDL_Quit) MinGW
- 如何在单例类中管理变量状态?
- 访问单例类C++时出现问题
- 基于 IOKit 的 kext 驱动程序中的单例类
- 指向抽象模板单例类的指针向量C++?
- C++在单例类中创建类实例时遇到困难
- 如果我这样写,我的单例类会导致什么错误
- 这是一个有效的单例类吗?
- 函数内具有静态变量的单例类(迈耶实现)
- 继承的模板化单例类 c++ 中未定义的构造函数
- 为什么调用单例类 Qt 消息处理程序成员函数会出现错误:缺少参数列表
- C++:单例类设计(错误:未解析的外部符号)
- 构造函数在不同线程中的静态单例类上调用两次
- 如何在自定义单例类中使用log4cplus
- 为什么在C 中创建单例类创建期间静态函数参考静态变量
- 如何在静态单例类中以编程方式从exec方法返回
- 为什么在单例类中私有析构函数
- 有效的单例类 ?