2011-03-07 76 views
9

当在C++头文件中有一个静态全局变量时,包含头文件的每个翻译单元都以其自己的变量副本结束。内联成员函数使用的静态全局变量

然而,如果我声明在同一标题文件中的类,并创建一个类的成员函数,类声明中的内联实现,它使用静态全局变量,例如:

#include <iostream> 

static int n = 10; 

class Foo { 
public: 
    void print() { std::cout << n << std::endl; } 
}; 

然后我看到下的gcc 4.4略微古怪的行为:

  1. 如果我编译不优化,成员函数的所有用途中使用该变量的副本从翻译单元中的一个(上g ++命令提到的第一个线)。

  2. 如果我使用-O2进行编译,每次使用成员函数都会使用来自作出该事件的翻译单元的变量副本。

显然这是非常糟糕的设计,所以这个问题只是出于好奇。但是,我的问题是,C++标准对这种情况说了些什么? g ++是否通过在启用和未启用优化的情况下提供不同的行为来正确行为?

+1

可能的重复:[h文件和内部链接中的静态关键字](http://stackoverflow.com/questions/4276794/static-keyword-in-h-file-and-internal-linkage)。 – 2011-03-07 11:49:33

回答

12

的标准说(3.2/5):一类型的

可以有多于一个的定义 (第9节), ...提供的定义满足 以下要求.. 。在d中的每个 定义,相应的名称, 抬头根据3.4,应 指d的定义 内定义一个实体,或应指 同一实体

这是您的代码丢失的地方。 nFoo的不同定义中的用法不涉及相同的对象。游戏结束,未定义的行为,所以是gcc有权在不同的优化级别做不同的事情。

3.2/5继续:

不同之处在于一个名称可以指 const对象与内部或没有 联动如果对象具有相同的 整数或枚举类型d的所有 定义,并且对象 以恒定表达 (5.19),并且该值被初始化(但不是 地址)所述对象的使用,和 对象具有在d

的所有 定义相同的值

因此,在您的示例代码中,您可以将n设置为static const int,并且所有这些都很可爱。本条款描述的条件并不是巧合,不同的TU是指“相同的对象还是不同的对象 - 它们所使用的全部是编译时常量值,它们都使用相同的值。

+1

+1:有时会以非常微妙的方式违反ODR – 2011-03-07 11:33:18

+0

优秀的答案。谢谢。 – jchl 2011-03-07 12:30:38