在单例模式中,什么使实例唯一?

时间:2019-04-24 18:02:31

标签: c++ compilation linker static-variables translation-unit

在实践中,单例模式是使用简单的静态函数创建的,该函数返回一个局部静态变量。只要实例是静态的,它就会在第一次函数调用期间返回一次定义的相同变量。

对我来说,令人困惑的部分是,如果我在一个头文件中声明带有静态局部变量的普通静态函数,并在调用该函数时将该头包含在两个不同的转换单元中,则该函数局部静态变量将被构造两次-每个函数翻译单位。

原因是在静态函数标识符中,函数链接是内部的,因此每个转换单元(源文件)都有该函数的两个实例,因此该静态变量有两个本地实例。

我的问题是,为什么相同的逻辑不适用于单例模式?当我们声明静态函数时,为什么它不是内部链接的,因此为什么不创建两个局部静态变量实例(根据定义,这是唯一的单例实例)?

我正在谈论的单个主要功能:

static className& instance() { static className instance; return instance; }

2 个答案:

答案 0 :(得分:1)

因为static [dcl.stc]/4并不总是意味着内部链接。当应用于普通的,命名空间范围的函数(如

)时
static void fun();  // fun has internal linkage

static说明符声明此函数具有内部链接[basic.link]/5。主要是为了实现与C的向后兼容性。在C ++中,您最好使用unnamed namespace声明具有内部链接的实体,以避免产生导致您提出问题的那种混乱:

namespace
{
    void fun();  // fun has internal linkage, C++ style
}

当应用于类的成员函数时,static说明符将函数声明为该类的static member function,即,一个不对那个类的实例进行操作但可以只是在该类的范围内声明的普通函数,例如:

class X
{
public:
    static void fun();  // fun is a static member function with external linkage
};

void test()
{
    X::fun();  // invoke fun
}

诸如命名成员函数之类的非命名空间范围的函数的链接不受关键字static的影响。结果,上面的静态成员函数将具有外部链接[basic.link]/6

除了所有这些:Singleton模式几乎肯定不是您要执行的操作的正确选择。 Don't do it.

答案 1 :(得分:-1)

返回单例的函数 不应是静态的,只能是单例本身。

这是不正确的

  db.<table_name>.find({},{_id:false,"IOT.measurements.svalue":"","IOT.measurements.units":""}).pretty()

此实现将导致每个编译单元返回不同的//header file - bad implementation of singleton pattern class foo {/*stuff*/}; static foo& getFoo() { static foo myFoo; return myFoo; } ,因为每个编译单元都有自己的myFoo函数

这是您应该做的:

getFoo

现在每个编译单元将引用相同的//header file - good implementation of singleton pattern class foo {/*stuff*/}; foo& getFoo(); //source file - good implementation of singleton pattern foo& getFoo() { static foo myFoo; return myFoo; } 函数并获得相同的单例(因为该函数不是静态的)


作为证明这一点的可测试示例。

getFoo