1

我正在研究一个我需要保证在各种翻译单元中的某些静态对象之前初始化(构造)的全局静态 std::vector 的情况。

当我查找如何处理这个问题时,我遇到了两个建议的解决方案:

  1. 在全局函数中有一个静态对象,用于代替全局静态对象。
  2. 施瓦茨计数器

我对使用 Schwarz 计数器的担忧是 std::vector 将被初始化两次。从此链接中我得到“确保全局对象仅在首次使用之前初始化一次的有用技术是保持对使用它的翻译单元数量的计数。”

全局只初始化一次是如何工作的?根据我的推理,它将被初始化两次。一次是在静态初始化的正常过程中,一次是在初始化 Schwarz 计数器的第一个实例时。

在相关说明中,初始化代码在 Schwarz 计数器构造函数中会是什么样子?我只能想到使用新的展示位置。

4

3 回答 3

1

我认为对于行为未定义的静态初始化问题没有正确答案,解决方案的选择取决于具体情况。这取决于:

  • 您的编译器及其实现
    • 大多数编译器在单个编译单元中提供保证
    • 顺序可以由链接器确定,有时会受到#pragma 的影响
    • 初始化可以在 main 开始执行之前的任何时候发生。
    • 是否将为具有静态变量的全局函数调用析构函数以及何时调用。
  • 应用架构
    • 无论使用 .DLL,某些环境都会减少对管理 DLL 中的静态构造/破坏的支持,尤其是在按需加载时。
    • 无论应用程序是线程的,这都会影响如何调用具有静态变量的全局函数。

可能最好的建议是通过以另一种方式设计您的系统来尝试避免这种惨败,尽管这可能不切实际。听起来您的应用程序确实不需要考虑一些关于可移植性的问题,而是针对具有特定编译器的特定环境。

#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(通过标头),并使用就地 new 进行初始化。应该注意确保漂亮的计数器是线程安全的(原子的)。

于 2013-08-21T13:30:55.387 回答
1

我只能说我过去是如何实现它的:我设计了一个特殊的“no-op”构造函数,它什么都不做,并在 Schwartz 计数器中使用放置 new。就像是:

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,但这通常不被认为是一个问题。

于 2013-08-12T17:57:35.813 回答
0

您可以使用另一个级别的间接:让您的全局变量成为指向向量的指针(将被零初始化),并让您的计数器new成为向量并将结果存储在指针中。

于 2013-08-12T19:10:01.320 回答