问题描述
我在macOS App的静态库中使用了一些c ++代码。 C ++代码包含以下内容:
static map<char*,char*> aMap1;
__attribute__((constructor))
static void initialize() {
{
static map<char*,char*> aMap2;
printf("map1: %d,map2: %d\n",aMap1.begin() == aMap1.end(),aMap2.begin() == aMap2.end()); // prints map1: 0,map2: 1
}
aMap1.begin()
不等于aMap1.end()
,即使aMap1.size()
为0。sizeof(aMap1)
为24,而&aMap1
处的24个字节为0。调用{ for循环之前的{1}}使aMap1.clear()
等于begin()
。
end()
等于aMap2.begin()
,并且字节不为零。
给我的印象是aMap1已自动初始化,但这似乎是不正确的?
解决方法
首先,__attribute__((constructor))
函数是实现定义的编译器扩展,因此C ++标准对理解其行为没有帮助。
Clang's attribute reference实际上并没有提及,因此我们不得不回到GCC's documentation,因为clang实现了此属性,以便与C / C ++ / Objective-C的GNU方言兼容
constructor
属性使函数在执行进入main()之前自动被调用。
到目前为止,相对于C ++静态初始化程序,没有指定相对顺序。但是,很快就会知道构造函数在 静态C ++初始化程序之前运行:
您可以提供一个可选的整数优先级[…]优先级编号较小的构造函数在优先级编号较大的构造函数之前运行; […]构造函数和析构函数的优先级与为名称空间范围的C ++对象指定的优先级相同(请参见C ++属性)。
如果您随后查看documentation for the init_priority()
attribute,则会发现其priority
自变量为:
[…]一个常数整数表达式,当前范围介于101和65535(含)之间。数字越小表示优先级越高。
换句话说,您可以将多个__attribute__((constructor))
函数以特定的相对顺序放置,优先级为0…100,并以101…65535的顺序静态初始化C ++对象,以覆盖在对象中初始化的对象的默认行为。编译单元中的定义顺序,而编译单元中未指定顺序。但这也意味着最后一个构造函数始终在第一个C ++静态初始化程序之前运行。
这说明了您看到的行为。您的构造函数在aMap1
的构造函数之前运行。 aMap1
是自动构建的,但要等到构造函数完成后才能实现。
有关解决此问题的方法,请参见the relevant entry in the C++ FAQ。
, someFunc
是从__attribute__((constructor))
函数中调用的,因此在aMap1
初始化程序之前被调用。为了解决该问题,我将代码移到了调度块。也可以从main
调用该函数,而不用将其标记为构造函数。
static map<char*,char*> aMap1;
__attribute__((constructor))
static void initialize() {
dispatch_async(dispatch_get_main_queue(),^{
static map<char*,char*> aMap2;
printf("map1: %d,map2: %d\n",aMap1.begin() == aMap1.end(),aMap2.begin() == aMap2.end()); // prints map1: 1,map2: 1
});
}