如果C ++头文件中有静态全局变量,则包含头文件的每个翻译单元都会以自己的变量副本结束。
但是,如果我在同一个头文件中声明一个类,并创建该类的成员函数,在类声明中实现内联,它使用静态全局变量,例如:
#include <iostream>
static int n = 10;
class Foo {
public:
void print() { std::cout << n << std::endl; }
};
然后我在gcc 4.4下看到了一些奇怪的行为:
如果我在没有优化的情况下编译,则所有成员函数的使用都使用其中一个翻译单元(g ++命令行中提到的第一个)的变量副本。
如果我使用-O2
进行编译,则每次使用成员函数都会使用来自翻译单元的变量副本。
显然这是一个非常糟糕的设计,所以这个问题只是出于好奇。但是,我的问题是,C ++标准对此案例的说法是什么?通过在启用和不启用优化的情况下提供不同的行为,g ++是否正常运行?
答案 0 :(得分:12)
标准说(3.2 / 5):
可以有多个定义 类的类型(第9条), ......如果定义满足 以下要求......各自 D的定义,相应的名称, 按照3.4,向上看 指在该中定义的实体 D的定义,或者指的是 同一实体
这是您的代码丢失的地方。 n
在Foo
的不同定义中的使用不是指同一个对象。游戏结束,未定义的行为,所以是的,gcc有权在不同的优化级别做不同的事情。
3.2 / 5继续:
除了名称可以引用a const对象有内部或没有 如果对象具有相同的链接 所有的积分或枚举类型 D的定义,对象是 用常量表达式初始化 (5.19),和值(但不是 使用对象的地址) 该对象具有相同的值 D的定义
因此,在您的示例代码中,您可以将n
变为static const int
并且一切都很可爱。这个子句描述了不同的TU是否“引用”相同的对象或不同的对象 - 它们使用的是编译时常量值并且它们都使用相同的对象的条件,这并不是巧合。 / p>