icd*_*dae 4 c++ initialization stdmap undefined-behavior c++11
我在一个旧程序中偶然发现了一些奇怪的行为,并弄清楚为什么G ++和CLang ++允许它发生.我在main()之前声明并初始化了一些全局变量.奇怪的是它们是通过静态std :: map初始化的,它使用下标运算符同时填充.一旦main()运行,一切似乎都在正确的位置,地图的大小显示正确的填充项数以及包含main()之前显示的值的变量.
#include <map>
#include <iostream>
static std::map<int, const char*> staticMap;
const char* const a = staticMap[0] = []()->const char* {return "a";}();
const char* const b = staticMap[1] = []()->const char* {return "b";}();
const char* const c = staticMap[2] = []()->const char* {return "c";}();
const char* const d = staticMap[3] = []()->const char* {return "d";}();
const char* const e = staticMap[4] = []()->const char* {return "e";}();
int main() {
std::cout << "# Items: " << staticMap.size() << '\n' << std::endl;
std::cout << "Values:\n";
std::cout << "\"a\" = " << a << '\n';
std::cout << "\"b\" = " << b << '\n';
std::cout << "\"c\" = " << c << '\n';
std::cout << "\"d\" = " << d << '\n';
std::cout << "\"e\" = " << e << '\n';
std::cout << std::endl;
std::cout << "Map Contents:" << std::endl;;
for (unsigned i = 0; i < 5; ++i) {
std::cout << "\t" << staticMap[i] << std::endl;
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这是尝试G ++和CLang之后的结果(我使用了标志-std = c ++ 11 -Wall -Werror -Wextra -pedantic-errors):
# Items: 5
Values:
"a" = a
"b" = b
"c" = c
"d" = d
"e" = e
Map Contents:
a
b
c
d
e
Run Code Online (Sandbox Code Playgroud)
这是C++本身允许的内容吗?我甚至创建了自己的地图类型并获得了相同的结果,但我仍然不确定它是否可以依赖它的行为.
这是完全正确的代码,虽然有点不寻常.该标准保证同一TU中的全局变量以声明顺序初始化(因此staticMap将在其他初始化发生之前构造),并且在初始化表达式中包含对重载运算符的调用并不奇怪.
实际上,所有lambdas的东西都是矫枉过正的,你可以这样做:
const char* a = staticMap[0] = "a";
const char* b = staticMap[1] = "b";
const char* c = staticMap[2] = "c";
const char* d = staticMap[3] = "d";
const char* e = staticMap[4] = "e";
Run Code Online (Sandbox Code Playgroud)
或者,甚至更简单:
const char *dummy = (
staticMap[0]="a",
staticMap[1]="b",
staticMap[2]="c",
staticMap[3]="d",
staticMap[4]="e");
Run Code Online (Sandbox Code Playgroud)
通常,main如果为此定义类,则可以执行之前所需的所有代码:
class MyCode
{
MyCode()
{
// here be your code
}
};
static MyCode m;
Run Code Online (Sandbox Code Playgroud)
但是要小心,调试代码在main启动之前运行通常是一个毛病的混乱,最好避免.在我最近的所有项目中,几乎没有代码在全局变量的构造函数中运行,更常见的是我只是创建相关的"全局变量"作为本地main变量并在全局变量中存储指向它们的指针.