Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 有效的单例类?;_C++_Design Patterns_Singleton - Fatal编程技术网

C++ 有效的单例类?;

C++ 有效的单例类?;,c++,design-patterns,singleton,C++,Design Patterns,Singleton,这是有效的单例类吗 class Singleton { private: static Singleton s; Singleton(){} public: static Singleton *getInstance() { return &s; } }; Singleton Singleton::s; 上面的三个单例类都是线程安全的,但它们都容易出现“静态初始化顺序失败”,对吗 这是有效的单例类吗 class Sin

这是有效的单例类吗

class Singleton
{
 private:
     static Singleton s;
     Singleton(){}
 public:
    static Singleton *getInstance()
    {
        return &s;
    }
};

Singleton Singleton::s;


上面的三个单例类都是线程安全的,但它们都容易出现“静态初始化顺序失败”,对吗

这是有效的单例类吗

class Singleton
{
 private:
     static Singleton s;
     Singleton(){}
 public:
    static Singleton *getInstance()
    {
        return &s;
    }
};

Singleton Singleton::s;
现在,在编辑之后,答案是肯定的,它是有效的&它也是线程安全的,因为所有非函数作用域静态变量都是在
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) 初始化发生。执行常量初始化:

-如果每个完整表达式(包括隐式转换) 出现在带有static或thread的引用的初始值设定项中 存储持续时间是一个常量表达式(5.19),引用为 绑定到指定具有静态存储持续时间的对象的左值 或临时(见12.2)

-如果初始化了具有静态或线程存储持续时间的对象 通过构造函数调用,如果构造函数是constexpr构造函数, 如果所有构造函数参数都是常量表达式(包括 转换),如果在函数调用替换(7.1.5)之后, mem初始值设定项中的每个构造函数调用和完整表达式,以及 在大括号或相等值中,非静态数据成员的初始值设定项是 恒定表达

-如果不支持具有静态或线程存储持续时间的对象 由构造函数调用初始化,如果 出现在其初始值设定项中的是一个常量表达式

零初始化和常量初始化一起被称为 静态初始化;所有其他初始化都是动态的 初始化。静态初始化应在任何 进行动态初始化。(……)

C++标准n3337§6.7/4:声明声明

所有具有静态变量的块范围变量的零初始化(8.5) 存储持续时间(3.7.1)或线程存储持续时间(3.7.2)为 在进行任何其他初始化之前执行。常数 使用静态存储初始化块范围实体(3.6.2) 持续时间(如果适用)在第一次执行其块之前执行 进入。允许实现提前执行 使用静态或线程初始化其他块作用域变量 与实施相同条件下的存储持续时间 允许使用static或thread静态初始化变量 命名空间范围中的存储持续时间。否则,这样的变量是 控件第一次通过其声明时初始化; 这样一个变量被认为是在它的操作完成时初始化的 初始化。如果初始化通过引发异常退出, 初始化未完成,因此将在下一次重试 时间控件进入声明如果控件输入声明 在初始化变量时,并发 执行应等待初始化完成*)。(…)

*):

实现不能在执行时引入任何死锁 初始化器

但它仍然很容易受到影响。编写
getInstance
的常用方法是:

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;
这样可以避免这个初始化问题

这是线程安全的单例类吗

class Singleton
{
 private:
     static Singleton s;
     Singleton(){}
 public:
    static Singleton *getInstance()
    {
        return &s;
    }
};

Singleton Singleton::s;
在C++11中,上述代码是线程安全的。在C++03中,可以使用


除此之外,还应防止复制和分配:

Singleton& getInstance()
{
    static Singleton instance;
    return instance;
}

据我所知,它是线程安全的。但它很容易受到影响

如果一个对象试图访问其构造函数中的
Singleton
,并且该对象是在程序初始化期间构造的,并且该代码位于
Singleton
之外的另一个编译单元中,则它可能会崩溃,也可能不会崩溃,因为
Singleton::s
可能尚未初始化(因为编译单元之间静态对象的初始化顺序未定义)。以下是一个示例:

Singleton( Singleton const&);      // Don't Implement
void operator=( Singleton const&); // Don't implement

这是懒惰的初始化Singleton,是的,它是线程安全的C++ 11。< /P>你能举个例子吗?@利泽克,我增加了一个例子。初始化的顺序问题是C++中使用单体的主要原因之一。“这是懒惰的初始化Singleton,是的……不,不是!在C++ 11之前,对象初始化可能是D。一对多线程上面的三个单例类都是线程安全的,但它们都容易“静态初始化顺序失败”,对吗?@Lizusekt它们在C++11(而不是C++03)中都是线程安全的,但在静态初始化顺序失败的情况下更容易发生@lizusek!