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;
上面的三个单例类都是线程安全的,但它们都容易出现“静态初始化顺序惨败”,我是对的吗?
答案 0 :(得分:6)
这是一个有效的单身人士课程吗?
现在,在编辑后答案是肯定的,它是有效的&它也是线程安全的,因为所有非函数范围的静态变量都是在main()
之前构造的,而只有一个活动线程。
C ++标准版n3337§3.6.2/1§3.6.2/ 2:非局部变量的初始化
有两大类命名的非局部变量:带有的变量 静态存储持续时间(3.7.1)和具有线程存储持续时间的那些 (3.7.2)。具有静态存储持续时间的非局部变量是 由于程序启动而初始化。非本地 具有线程存储持续时间的变量初始化为a 线程执行的结果。在每个启动阶段中,初始化发生如下。
具有静态存储持续时间(3.7.1)或线程存储的变量 持续时间(3.7.2)应在任何其他之前进行零初始化(8.5) 初始化发生。执行常量初始化:
- 如果每个完整表达式(包括隐式转换)那个 出现在带有静态或线程的引用的初始值设定项中 存储持续时间是一个常量表达式(5.19),参考是 绑定到左值,指定具有静态存储持续时间的对象 或临时(见12.2);
- 如果初始化具有静态或线程存储持续时间的对象 通过构造函数调用,如果构造函数是constexpr构造函数, 如果所有构造函数参数都是常量表达式(包括 转换),如果在函数调用替换后(7.1.5), mem-initializers中的每个构造函数调用和完整表达式 在非静态数据成员的brace-or-equal-initializers中是一个 恒定表达;
- 如果具有静态或线程存储持续时间的对象不是 由构造函数调用初始化,如果每个完整表达式 在其初始化器中出现的是一个常量表达式。
一起调用零初始化和常量初始化 静态初始化;所有其他初始化都是动态的 初始化。静态初始化应在任何之前执行 动态初始化发生。 (...)
C ++标准版n3337§6.7/ 4:声明声明
使用static的所有块范围变量的零初始化(8.5) 存储持续时间(3.7.1)或线程存储持续时间(3.7.2)是 在任何其他初始化发生之前执行。不变 具有静态存储的块范围实体的初始化(3.6.2) 持续时间(如果适用)在其块首次执行之前执行 进入。允许实现尽早执行 使用static或thread初始化其他块作用域变量 在与实现相同的条件下的存储持续时间 允许使用static或thread静态初始化变量 命名空间范围内的存储持续否则这样的变量是 初始化第一次控制通过其声明; 这样的变量在完成后被认为是初始化的 初始化。如果通过抛出异常退出初始化, 初始化未完成,因此下次将再次尝试 时间控制进入声明。 如果控制进入声明 在初始化变量的同时,并发 执行应等待初始化完成*)。(...)
*):
实现不得在执行时引入任何死锁 初始化器。
但仍然容易static initialization order fiasco。写getInstance
的常用方法是:
Singleton& getInstance()
{
static Singleton instance;
return instance;
}
这样可以避免这种初始化问题。
这是一个线程安全的单例类吗?
在上面的C ++ 11中,代码是线程安全的。在C ++ 03中,您可以使用
除此之外,你还应该防止复制和分配:
Singleton( Singleton const&); // Don't Implement
void operator=( Singleton const&); // Don't implement
答案 1 :(得分:3)
据我所知,这是线程安全的。但它易受static initialization order fiasco的影响。
如果某个对象试图在其构造函数中访问Singleton
并且该对象是在程序初始化期间构造的,并且此代码位于Singleton
之外的另一个编译单元中,则它可能会崩溃,也可能不会崩溃,因为{{1可能已经或者可能尚未初始化(因为未定义编译单元中静态对象的初始化顺序)。这是一个例子:
Singleton::s
答案 2 :(得分:0)
这是懒惰的初始化Singleton,是的。它在C ++ 11下是线程安全的。