我正在研究一个案例,我将有一个全局静态std :: vector,我需要保证在各种翻译单元中的某些静态对象之前进行初始化(构造)。
当我查看如何处理这个问题时,我遇到了两个建议的解决方案:
我对使用Schwarz计数器的担心是std :: vector将被初始化两次。从this链接我得到“一种有用的技术,用于确保全局对象仅在初次使用时初始化一次,以保持使用它的翻译单元数量。”
全局只被初始化一次是如何工作的?根据我的推理,它将被初始化两次。一旦进入静态初始化的正常过程,一次初始化Schwarz计数器的第一个实例。
在相关的说明中,初始化代码在Schwarz计数器构造函数中会是什么样的?我只能想到使用新的展示位置。
答案 0 :(得分:1)
我只能说我过去如何实现它:我设计 一个特殊的“无操作”构造函数,它什么都不做,并且使用 在Schwartz柜台安置新品。类似的东西:
class ForUseAsStatic
{
public:
enum MakeCtorNoop { makeCtorNoop };
ForUseAsStatic(); // normal ctor, called by Schwartz counter.
ForUseAsStatic( MakeCtorNoop );
// no-op constructor, used when
// defining the variable.
};
形式上,这不能保证 - 允许编译器 在调用构造函数之前再次将内存设置为0, 但我从来没有听说过编译器。
也可以在课堂上放一些旗帜 本身,由构造函数测试。这只适用于 当然是静态对象(因为它需要零初始化) 为了工作)。
另一种可能的技术(我在一些人看到过这种技术) 库)是为对象声明内存 汇编程序,或者如果编译器有一些方法,则作为字节数组 强迫对齐。数据名称通常不会被破坏,所以这个 通常会工作,即使它是正式未定义的行为。 (对于标准库,当然,库作者可以 在编译器中请求扩展以帮助他们 问题)。
最后:今天,单身成语或类似的东西是
通常倾向于这种解决方法。它确实意味着你
必须写myobj().xxx
,而不仅仅是myobj.xxx
,但是
这通常不被认为是一个问题。
答案 1 :(得分:1)
我认为静态初始化问题没有正确的答案,行为未定义,解决方案的选择取决于具体情况。这取决于:
可能最好的建议是通过以另一种方式设计您的系统来避免这种惨败,尽管这可能不实用。听起来你的应用程序不需要考虑一些关于可移植性的问题,而是针对特定编译器的特定环境。
#pragma /编译器选项
您可能没有考虑过的一个选项是,是否有一些编译器支持您需要的内容。
对于Windows,请参阅: http://support.microsoft.com/kb/104248
对于g ++:
启用init-priority
并使用__attribute__ ((init_priority (n)))
。
让Swartz计数器正常工作
一些例子省略的是空间的对象只是为被正确对齐的被分配对象保留。这避免了你提到的一个结构。例如,在g ++ gnu中使用:
typedef char fake_istream[sizeof(istream)] __attribute__ ((aligned(__alignof__(istream))))
...
fake_istream cin;
为对象分配空间。编译单元外部的所有代码都将此区域称为extern istream cin
(通过标题),并使用就地新的初始化。应该注意确保漂亮的计数器是线程安全的(原子)。
答案 2 :(得分:0)
你可以使用另一个间接级别:让你的全局变量是一个指向vector的指针(它将被零初始化),并让你的计数器new
为向量并将结果存储在指针中。 / p>