如何等待静态变量的动态初始化完成

V_V*_*V_V 5 c++

根据其他来源的资料,C++区分了两种静态变量的初始化:

  • static - 如果变量是通过将其置于可执行文件中的特殊部分的初始值中来初始化的。

  • 动态 - 如果静态变量的初始值也已计算

关于动态初始化构造函数调用的顺序有很多讨论。但是我没有找到有关如何等到可执行文件中所有静态变量的所有动态初始化完成的信息。或者从另一方面如何以间接/通用方式手动调用此初始化。

我使用静态变量初始化来实现插件架构的松散耦合。我有 plugin1.c, plugin2.c ... 和plugin1.c static bool installed = plugin1_install();里面的静态变量

但在主要我需要等到所有插件安装。

这里建议了我使用的相同内容1。作为以下问题的答案

我想为我的程序编写一个共享库。但是,在调用库中的任何其他函数之前,我需要库具有一些自初始化例程...

回答:

C++ 本身支持事物的全局初始化。您可以执行以下操作:

int global_variable=some_global_function();

这在 C 中是非法的,但在 C++ 中是合法的。

我可以在 的帮助下实现我需要的功能__CTOR_LIST__吗?

Mar*_*ork -1

不幸的是,该语言不支持这些语义。

静态存储持续时间对象SSDO(静态和动态初始化)仅保证在使用前初始化。该标准在 中描述了订购约束和保证[basic.start.init]

下面描述了如何将动态初始化推迟到 main 之后。

(n2723) 3.6.2 非本地对象的初始化 [basic.start.init]

第4段

具有静态存储持续时间的命名空间范围的对象的动态初始化(8.5、9.4、12.1、12.6.1)是否在 main 的第一个语句之前完成是实现定义的。如果初始化被推迟到 main 的第一个语句之后的某个时间点,则它应在首次使用与要初始化的对象相同的翻译单元中定义的任何函数或对象之前发生。

实际上,只要您的对象没有副作用,您就可以编写代码,就好像它们都在 main 之前初始化一样(因为尝试访问它们将导致它们的初始化(您的代码不需要显式操作))。如果它们有副作用,那么不要依赖副作用的发生。

如果您依赖副作用,那么您可以利用 main() 的位置。
只需将所有 SSDO 对象声明在与 main() 相同的文件中即可。因为它们位于同一翻译单元中,所以现在必须在输入 main 之前对它们进行初始化。

以这种方式编写(或原因之一)是为了允许使用动态加载共享库(dll),而无需明确将共享库的概念写入标准。由于在进入 main() 之前可执行文件中不存在动态加载的共享库,因此无法在 main() 之前初始化其 SSDO。标准的上述部分考虑到了这一事实。尽管它确实保证任何 SSDO 在使用之前都会被初始化。

共享库

当然,标准中没有定义有关共享库 (dll) 的任何内容,因为这些组件不直接与语言相关,而是操作系统提供的功能。

话虽如此。大多数操作系统在加载共享库时(通过标准共享库加载机制,即 dlopen())将在加载共享库的函数调用返回之前初始化所有 SSDO。在 SSDO 初始化被推迟的情况下,它将遵守上面定义的规则[basic.start.init]

初始化顺序:

初始化的顺序通常并不重要。

除非您在初始化(或销毁)另一个 SSDO 期间使用 SSDO。那么顺序确实变得很重要,因为您需要确保所使用的对象在使用之前已被创建/初始化(否则其数据是垃圾)。

你有几个选择。如果 SSDO 位于同一翻译单元中,则可以按照它们在翻译单元中声明的顺序定义初始化顺序:

// File OneFile.cpp
myClass2 gv_2   = some_othere_global_function();
myClass1 gv_1   = some_global_function(); // If this uses gv_2 it must be declared first
Run Code Online (Sandbox Code Playgroud)

如果它们位于不同的翻译单元中,那么您无法保证顺序:

// File 1.cpp
myClass1 gv_1   = some_global_function(); // If this uses gv_2 you may have a problem.

// File 2.cpp
myClass2 gv_2   = some_othere_global_function();
Run Code Online (Sandbox Code Playgroud)

顺序问题可以通过使用函数来解决:

// File 1.cpp
myClass1& get_gv_1()
{
    static myClass1 gv1 = some_global_function();  // This function can only access gv2
                                                   // by calling get_gv_2(). This will of
                                                   // force dynamic creation of the object
                                                   // this it is guaranteed to be initialized.
    return gv1;
}

// File 2.cpp
myClass2& get_gv_2()
{
    static myClass2 gv2 = some_othere_global_function();
 // ^^^^^^
 //    Notice the use of static here.
 //    This means the object is created the first time the function
 //    is called (and destroyed on application exit).
 //
 //    All subsequent calls will just use the same value.
 //    Note the return type. We return a reference to the object.
    return gv2;
}
Run Code Online (Sandbox Code Playgroud)

另请参阅:

  • 一般来说,“在命名空间范围内”仅仅意味着“不在函数/类中”。仅根据这句话,我并没有得出这样的结论:全局命名空间中的变量比任何其他命名空间中的变量具有更多的保证。而且我绝对没有看到任何表明整个命名空间已初始化的信息,而不仅仅是单个翻译单元。我手边没有标准的副本,所以也许我遗漏了上下文中的一些内容。 (2认同)