我们有一个C ++库。它有四个对初始化顺序敏感的静态对象(其中两个是标准库中的字符串)。
我们使用init_seg(lib)
来控制库中C ++静态对象的初始化顺序。使用它的源文件在动态链接库或静态库中编译和使用。根据{{1}}的文档:
...在需要初始化的 动态链接库(DLL)或库 中使用init_seg编译指示尤为重要。 (强调我的)
Visual Studio解决方案分为四个项目。一个是静态库,或者是动态库,一个是静态库的测试驱动程序,一个是动态库的测试驱动程序。
在Visual Studio下,使用init_seg
编译源文件会导致warning C4073,文本初始化程序将放入库初始化区域。根据MSDN:
只有第三方库开发人员才能使用库初始化区域,该区域由#pragma init_seg指定。以下示例生成C4073 ...
使用init_seg
的代码仅在库中使用, 不 与测试驱动程序一起使用。我已经验证了静态库和动态库项目设置,它们显然正在调用库工件。
为什么我收到C4073警告?
答案 0 :(得分:0)
它只是警告你,甚至不是手指的摇摆,它更像是“你确定吗?”当您使用使用此功能的第三方库时,它也会警告其开发人员 - 除非他使用#pragma warning
将其关闭。你也可以这样做。或者您可以使用细分user
而非细分lib
:您的字符串仍将在您的应用程序代码运行之前构建。段lib
实际上是用于......哦,Qt或MFC或类似的框架,需要在任何应用程序代码运行之前进行初始化,包括{}中的早期初始化内容{1}}。
以下是更多信息:
假设您有自己的应用程序库。并且它有一些在运行任何代码之前需要初始化的东西,因为这个库公开的某些类旨在(或者,允许)在应用程序代码中静态分配,并且这些类做复杂的东西在他们的构造函数中,需要一些预计算(但不是静态)数据的大量bollix。所以对于那些预先计算的东西,你在类的构造函数(一个不同的类)中预先计算它,你静态地分配该类的一个实例,这样该实例的初始化调用它的构造函数,它预先计算所有的东西,而那个静态实例你用user
标记。现在,在您的任何应用程序代码运行之前 - 包括代码中此库的类的静态实例的任何构造函数 - 库的pragma init_seg(user)
代码将全部运行,因此,当此库的类的静态实例获得时构建了他们需要的数据。
现在考虑一下真正必须提前出现的东西,其中存在可以调用的静态实例。例如,init_seg(user)
。您可以在您拥有静态实例的类的构造函数中调用std::cout
上的方法。显然,在任何代码运行之前,需要初始化对象std::cout
。您的一些代码可能会在标记为std::cout
的内容中运行。因此,Microsoft在init_seg(user)
中放置了所有此类代码 - 即std::cout
等的构造函数。那些东西将在任何东西之前运行。
那么init_seg(compiler)
是什么?好吧,假设你是一个像MFC这样的框架。您公开了类似于Application对象的东西,用户将(可能会,希望)创建一个静态实例。 Application中将在静态初始化时运行的一些代码取决于MFC中需要初始化的其他内容。显然它需要init_seg(lib)
ged,但在哪里? init_seg
仅用于编译器和运行时,并且您的框架内容(MFC)可能在允许用户使用的compiler
中使用...因此您获得{{1}之间的中间级别}和init_seg(user)
- 那是compiler
。
现在很少需要这样的东西,因为程序使用的大多数C ++库本身并不被多个库使用,因此不需要确保它们在所有其他“普通”库之前初始化。 MFC确实如此,因为您可能已经从一个或多个供应商处购买了第三方MFC控件或其他库,并且这些库依赖于MFC,并且那些可能在其构造函数中使用MFC,并且您可能静态地使用这些库中的对象,因此MFC需要在其他库之前初始化。
但在大多数情况下,您的库不会成为人们正在使用的其他 C ++库的依赖项。因此,没有任何类型的依赖链,您的库需要在其他库之前初始化。您的库可能需要在用户代码之前初始化,是的,但是没有任何需要初始化的顺序。所以user
适用于所有人。
而且,Microsoft(以及一般来说,大多数C ++专家)会告诉您:如果 某种顺序依赖,其中您需要在静态时初始化的单独库初始化你的应用然后你做错了。认真。那里有一个设计问题。
所以,回应评论:这不是编译错误。这是用户警告。相当温和:如果你忽略了它就不会出错(不像是忽略了关于从long转换为int的警告)。但是如果你使用lib
,你可能并不真正理解编译器功能的全部内容,所以他们希望你考虑一下。在您考虑之后,如果您仍想这样做,请继续关闭警告。