c++中不一致的文件作用域变量行为
Inconsistent file-scoped variable behavior in C++
标题可以改进,但我不确定问题是什么。欢迎提出建议。我有一个自定义枚举类,Color
:
// Color.h
class Color {
protected:
int id;
Color(int id) : id(id) {}
void operator&(); //undefined
public:
Color(const Color& r) : id(r.id) {}
Color& operator=(const Color& r) {id=r.id; return *this;}
bool operator==(const Color& r) const {return id==r.id;}
bool operator!=(const Color& r) const {return id!=r.id;}
operator int() const {return id;} //so you can still switch on it
static Color Blue;
static Color Red;
};
// Color.cpp
#include "Color.h"
Color Color::Blue(0);
Color Color::Red(1);
在main
中,我有一个Colors
的文件作用域数组。当我在文件作用域数组中打印Colors
的值时,一切都是正确的:
// main.cpp
#include "Test.h"
using namespace std;
const Color mainColors[] = {Color::Red, Color::Red }; // values should be [1, 1]
int main()
{
cout << "Main file-scoped colors: " << mainColors[0] << ", " << mainColors[1] << endl; // prints [1, 1]
Test();
return 0;
}
然而,如果我尝试在另一个文件Test
中做同样的事情,它不起作用。当我打印文件作用域数组时,值是不正确的,就好像它们没有初始化一样。:
// Test.h
#include "Color.h"
void Test();
// Test.cpp
#include "Test.h"
const Color fooColors[] = {Color::Red, Color::Red}; // values should be [1, 1]
void Test()
{
cout << "Test file-scoped colors: " << fooColors[0] << ", " << fooColors[1] << endl; // prints [0, 0]
}
我在这里做错了什么?我认为这可能与枚举成员是静态的有关,但我不能把我的手指放在上面。
您看到的问题是静态变量初始化顺序未指定的结果。
行为可以很容易地改变构建系统的细微变化(例如调试与非调试,添加另一个文件到程序,等等)
看起来main.cpp
中的mainColors
在Color::Red
和Color::Blue
初始化之后才被初始化,Test.cpp
中的fooColors
在Color::Red
和Color::Blue
初始化之前被初始化。
变通(感谢@Andy)
增加static
成员函数Blue()
和Red()
到Color
。使用它们来初始化main.cpp
和Test.cpp
中的变量
In Color.h
:
static Color Blue();
static Color Red();
In Color.cpp
:
Color Color::Blue() {return Color(0);}
Color Color::Red() {return Color(1);}
In main.cpp
:
const Color mainColors[] = {Color::Blue(), Color::Red() };
In Test.cpp
:
const Color fooColors[] = {Color::Blue(), Color::Red()};
这与枚举成员是静态的有关。在翻译单元中,静态成员数据的初始化顺序是未定义的。基本上,第一次调用(main)是幸运的,而第二次调用(Test.cpp)是不幸的。有几种方法可以解决这个问题,但这是最重要的。
在这个特殊的情况下,Test fooColors首先使用Color类中的未初始化的静态数据进行初始化。这个数据然后被初始化,然后最后mainColors从Color::red和Color::blue中初始化。
- 在类函数中初始化外部作用域变量
- 不同作用域中的静态变量和全局变量
- 未在此作用域中声明的函数和变量 (C++)
- 如何在C++中访问作用域的变量输出?
- 不同块作用域中的 C++ 变量具有相同的地址
- C++If语句变量作用域
- 派生类变量作用域 c++
- 如何理解C++变量作用域规则
- C/C++编译器关于变量作用域的优化
- 应用程序有2个静态变量作用域
- 堆变量作用域
- c++中变量作用域的机制
- c++变量作用域的类友
- 函数所需的总堆栈大小如何与变量作用域相关
- 声明友元函数时出现变量作用域错误
- 引用的C++变量作用域
- c++中的变量作用域
- c/c++中局部变量作用域和生命周期的混淆
- c++中的局部/静态变量作用域
- 多个c++文件和变量作用域