c++ - 一个有效的单例类?

标签 c++ design-patterns singleton

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;

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

最佳答案

Is this a valid singleton class?

现在,编辑后答案是肯定的,它是有效的并且也是线程安全的,因为所有非函数范围的静态变量都是在 main() 之前构造的,而只有一个事件线程。

C++ 标准 n3337 § 3.6.2/1 § 3.6.2/2:非局部变量的初始化

There are two broad classes of named non-local variables: those with static storage duration (3.7.1) and those with thread storage duration (3.7.2). Non-local variables with static storage duration are initialized as a consequence of program initiation. Non-local variables with thread storage duration are initialized as a consequence of thread execution. Within each of these phases of initiation, initialization occurs as follows.

Variables with static storage duration (3.7.1) or thread storage duration (3.7.2) shall be zero-initialized (8.5) before any other initialization takes place. Constant initialization is performed:

— if each full-expression (including implicit conversions) that appears in the initializer of a reference with static or thread storage duration is a constant expression (5.19) and the reference is bound to an lvalue designating an object with static storage duration or to a temporary (see 12.2);

— if an object with static or thread storage duration is initialized by a constructor call, if the constructor is a constexpr constructor, if all constructor arguments are constant expressions (including conversions), and if, after function invocation substitution (7.1.5), every constructor call and full-expression in the mem-initializers and in the brace-or-equal-initializers for non-static data members is a constant expression;

— if an object with static or thread storage duration is not initialized by a constructor call and if every full-expression that appears in its initializer is a constant expression.

Together, zero-initialization and constant initialization are called static initialization; all other initial- ization is dynamic initialization. Static initialization shall be performed before any dynamic initialization takes place. (...)

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

The zero-initialization (8.5) of all block-scope variables with static storage duration (3.7.1) or thread storage duration (3.7.2) is performed before any other initialization takes place. Constant initialization (3.6.2) of a block-scope entity with static storage duration, if applicable, is performed before its block is first entered. An implementation is permitted to perform early initialization of other block-scope variables with static or thread storage duration under the same conditions that an implementation is permitted to statically initialize a variable with static or thread storage duration in namespace scope. Otherwise such a variable is initialized the first time control passes through its declaration; such a variable is considered initialized upon the completion of its initialization. If the initialization exits by throwing an exception, the initialization is not complete, so it will be tried again the next time control enters the declaration. If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization*). (...)

*):

The implementation must not introduce any deadlock around execution of the initializer.

但还是容易出现static initialization order fiasco . getInstance的常用写法是:

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

这样你就可以避免这个初始化问题。

Is this a thread-safe singleton class?

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

pthread_once


除此之外你还应该防止复制和赋值:

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

关于c++ - 一个有效的单例类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22783166/

相关文章:

c++ - 以 O(n^3 log n) 的运行时间执行 2 个循环

c++ - 从字符串中过滤掉 url

c++ - C++ 所需的具有 C 链接的回调函数

c++ - 对单例模式的这方面感到困惑

c++ - 使用 C++ 逗号运算符将语句替换为表达式是否可以允许更多的编译器优化?

c++ - 当两个shared_pointer实例被删除时,删除由两个shared_pointer实例管理的对象

java - 具有一些完全相似方法的工厂设计模式

java - 有什么办法可以避免转换这种类型?

design-patterns - 超链接与按钮

javascript - 将多个实体从不同的文件添加到 JavaScript 命名空间