在实例之间共享方法的本地静态变量的任何风险?

时间:2016-05-06 14:44:56

标签: c++ methods static-variables

让我说我创造:

class Hello {
    public:
        int World(int in)
        {
            static int var = 0;    // <<<< This thing here.
            if (in >= 0) {
                var = in;
            } else {
                cout << var << endl;
            }
        }
};

现在,如果我这样做:

Hello A;
Hello B;

A.World(10);
A.World(-1);
B.World(-1);

我输出“10”后跟另一个“10”。方法的 local 变量的值刚刚从一个类的实例跨越到另一个实例。

这并不奇怪 - 技术上方法只是具有隐藏this参数的函数,因此静态局部变量的行为应该与常用函数一样。但它保证?它是由标准强制执行的行为,还是仅仅是编译器处理方法的快乐副产品?换句话说 - 这种行为是否可以安全使用? (...超出了让人不习惯的标准风险......)

4 个答案:

答案 0 :(得分:3)

是。如果函数是一个类的[非静态]成员并不重要,那么它只保留一个实例的静态变量。

对这些变量的正确技术解释是那些变量是具有static durationinternal linkage的对象 - 因此这些名称会在程序退出之前存在,并且此名称的所有实例都指向同一实体。

答案 1 :(得分:1)

只需添加一个正确答案即可。如果您的类是模板化的,那么var的实例只能在相同实例化类型的对象之间共享。所以如果你有:

template<typename C>
class Hello {
    public:
        int World(int in)
        {
            static int var = 0;    // <<<< This thing here.
            if (in >= 0) {
                var = in;
            } else {
                cout << var << endl;
            }
        }
};

然后:

Hello<int> A;
Hello<int> B;
Hello<unsigned> C;

A.World(10);
A.World(-1);
B.World(-1);
C.World(-1);

然后最终输出将是“0”而不是“10”,因为Hello<unsigned>实例化将拥有自己的var副本。

答案 2 :(得分:0)

如果我们谈论的是Windows编译器,那么保证

https://msdn.microsoft.com/en-us/library/y5f6w579.aspx

  

以下示例显示了在成员函数中声明为static的局部变量。静态变量可用于整个程序;该类型的所有实例共享静态变量的相同副本。

他们使用的示例与您的示例非常相似。

我不知道GCC

答案 3 :(得分:0)

是的,保证。现在,回答问题&#34;在实例之间共享方法的本地静态变量的任何风险?&#34;它可能不那么直截了当。初始化和利用变量可能存在潜在风险,这些风险特定于方法的本地变量(而不是类变量)。

对于初始化,标准中的相关部分是6.7 / 4 [stmt.dcl]:

  

使用静态存储动态初始化块范围变量   执行持续时间(3.7.1)或线程存储持续时间(3.7.2)   第一次控制通过其声明;这样的变量是   在初始化完成时考虑初始化。如果   初始化通过抛出异常退出   是不完整的,所以下次控制时会再次尝试   进入宣言。如果控件同时进入声明   在初始化变量时,并发执行   应等待初始化完成。如果控制   在变量存在时递归地重新输入声明   初始化后,行为未定义。

在简单的情况下,一切都应该按预期工作。当变量的构造和初始化更复杂时,将存在特定于此情况的风险。例如,如果构造函数抛出,它将有机会在下一次调用时再次抛出。另一个例子是递归初始化,这是未定义的行为。

另一个可能的风险是该方法的性能。编译器需要实现一种机制来确保变量的兼容初始化。这是依赖于实现的,它很可能是一个锁,用于检查变量是否已初始化,并且每次调用该方法时都可以执行锁定。当发生这种情况时,它会对性能产生重大不利影响。