C++ 控制静态对象的顺序';建造师
我正在用c++11编写一个小型内核,并且有两个相同类型的实例,必须在创建任何其他静态对象之前构建它们 我写的代码如下:C++ 控制静态对象的顺序';建造师,c++,constructor,c++11,C++,Constructor,C++11,我正在用c++11编写一个小型内核,并且有两个相同类型的实例,必须在创建任何其他静态对象之前构建它们 我写的代码如下: // test.hpp class test { // blahblah... }; // test.cpp typedef char fake_inst[sizeof(test)] __attribute__((aligned(alignof(test)))); fake_inst inst1; fake_inst inst2; // main.cpp extern
// test.hpp
class test {
// blahblah...
};
// test.cpp
typedef char fake_inst[sizeof(test)] __attribute__((aligned(alignof(test))));
fake_inst inst1;
fake_inst inst2;
// main.cpp
extern test inst1;
extern test inst2;
int kmain() {
// copy data section
// initialize bss section
new (&inst1) test();
new (&inst2) test();
// call constructors in .init_array
// kernel stuffs
}
它按照预期构建和工作,没有任何警告消息,但不支持LTO
我收到了大量的警告消息,抱怨类型匹配,我想知道是否有解决办法,因为它会让我难以找到其他“真实”的警告或错误消息
有什么建议吗?您能使用GCC的
init\u priority
属性吗
Some_Class A __attribute__ ((init_priority (2000)));
Some_Class B __attribute__ ((init_priority (543)));
//在.h文件中
typedef char fake_inst[sizeof(test)]__属性(aligned(_alignof__(test)));
外部假冒伪劣;
外部假冒伪劣2;
内联测试&f_inst1(){return*reinterpret_cast(fake_inst1);}
内联测试&f_inst2(){return*reinterpret_cast(fake_inst2);}
//和可读性
静态测试和inst1(f_inst1());
静态测试和inst2(f_inst2());
希望
inst1
和f_inst1()
都能得到优化。C++没有提供管理多个文件中全局对象初始化顺序的方法。如果您需要如此严格地管理这些对象的初始化顺序,那么我强烈建议您不要将它们设置为全局对象。使它们成为包含静态对象并返回指向它们的指针的全局函数
但即便如此,这也没有完全手动初始化那么危险。只需为那些需要它们的人提供一些指向这些对象的指针(最好不是全局指针),您就可以了。也许像这样
// ... .h
template<typename T>
union FakeUnion {
FakeUnion() {}
~FakeUnion() {}
T inst;
};
extern FakeUnion<test> inst1_;
extern FakeUnion<test> inst2_;
static constexpr test& inst1 = inst1_.inst;
static constexpr test& inst2 = inst2_.inst;
// ... .h end
// ... .cpp
FakeUnion<test> inst1_;
FakeUnion<test> inst2_;
// ... .cpp end
/。H
模板
联盟伪造联盟{
伪联合(){}
~FakeUnion(){}
T inst;
};
外部伪造联合研究所;
外部伪造联合研究所;
静态constexpr测试&inst1=inst1_u2;inst;
静态constexpr测试&inst2=inst2_u2;inst;
// ... .h端
// ... .cpp
假联合研究所;
伪造联合研究所;
// ... .cpp端
在
main
中,您可以说new(&inst1)test代码>。它现在不应该再发出关于类型不一致性冲突的警告,因为与代码中的不同,这段代码不包含在不同文件中具有不同类型的变量。我读过这方面的内容,但很难管理构造函数的顺序,因为优先级分布在源文件中。@kukyakya所以问题是首先初始化两个对象,或者总体上对所有全局构造函数进行排序?@Potatoswatter实际上,这不仅仅是两个实例,而是同一类型的多个实例,所以我不能使用单例模式。其他静态对象的构造顺序无关紧要。我考虑过使用全局函数返回函数作用域静态对象的引用或指针,但编译器生成acquire/release来创建实例,acquire/release使用内核互斥实现,不能在内核初始化中使用。@kukyakya:那么您必须手动初始化这些对象。这是确保没有内核互斥体的唯一方法。这正是我使用的方法,但我想知道是否有更整洁的方法。我想要像std::cout
或std::cin
这样的全局对象,因为它看起来比实例返回函数更可读。可以尝试全局引用变量,初始化为inst1
的retval?这也是优化的(在msvc中)全局变量的问题是它们的初始顺序,这就是我们试图解决的…@n.m.:正确点。但在这种特殊情况下,这没关系。引用本身是一个全局变量,它在占位符的main
之前初始化。您真正想做什么?在下面对Pubby答案的评论中,您说您想初始化几个相同类型的对象。对我来说,似乎您想初始化与C++支持相关的结构,例如堆,然后让实现调用其他构造函数。但这听起来不像你要尝试的。还有,你会得到关于什么类型的“类型匹配”的警告?@Potatoswatter很多警告:“xxx”的类型与原始声明不匹配[默认启用]
事情。这是因为实际类型不是test,而是char[]。我以为我可以禁用静态构造函数,但似乎没有办法。啊,我明白了。你应该做的是char fake_inst1[sizeof(test)];测试*const inst1=钢筋混凝土浇筑<测试*>(假inst1)代码>禁用静态构造函数的方法是将变量放入包装函数中。只有在第一次调用包装器时才会调用构造函数。这是非常惯用的方法,总是比在名称空间范围中放置全局名称空间更可取。但是,在您的情况下,您需要确保在运行时支持用于实现“仅第一次”功能的多线程操作。无论您是否找到抑制警告的方法,这都是处理具有非平凡c'tor/d'tor的全局/静态对象的唯一真正正确的方法。这样不仅可以控制它们的初始化/销毁顺序,还可以实际控制程序流。例如,您可以从它们的初始化代码中抛出异常,并适当地捕获它们。所有这些都不会影响性能。虽然这确实解决了名称冲突,但它不能确保在调用任何其他构造函数之前调用inst1
和inst2
。@Matt如果他在main
中调用它们,并使用新的位置,如果以受控的方式在main
之后调用所有其他的CTOR,它确实可以确保这一点。您能就这里发生的“魔力”给出建议吗?也就是说,为什么我们需要工会,为什么工会有ctor/dtor?
// ... .h
template<typename T>
union FakeUnion {
FakeUnion() {}
~FakeUnion() {}
T inst;
};
extern FakeUnion<test> inst1_;
extern FakeUnion<test> inst2_;
static constexpr test& inst1 = inst1_.inst;
static constexpr test& inst2 = inst2_.inst;
// ... .h end
// ... .cpp
FakeUnion<test> inst1_;
FakeUnion<test> inst2_;
// ... .cpp end