init_seg和从库代码警告C4073?

我们有一个C ++库。 它有四个对初始化顺序敏感的静态对象(其中两个是来自标准库的string)。

我们使用init_seg(lib)来控制库中C ++静态对象的初始化顺序。 正在使用它的源文件在dynamic链接库或静态库中进行编译和使用。 根据init_seg的文档:

…在需要初始化的dynamic链接库(DLL)或库中使用init_seg编译指示尤为重要。 (重点是我的)

Visual Studio解决scheme分为四个项目。 一个是静态库,或者是dynamic库,一个是静态库的testing驱动程序,一个是dynamic库的testing驱动程序。

在Visual Studio下,使用init_seg编译源文件init_seg产生警告C4073 ,并将文本初始值设定项放入库初始化区域 。 根据MSDN:

只有第三方库开发人员应该使用由#pragma init_seg指定的库初始化区域。 以下示例生成C4073 …

使用init_seg的代码仅在库中使用, 不能与testing驱动程序一起使用。 我已经validation了静态库和dynamic库项目设置,并且明确地调用了库工件。

为什么我收到C4073警告?

这只是警告你,甚至不是一个手指的摇摆,更像是“你确定吗?” 当您使用使用此功能的第三方库时,也会警告其开发者 – 除非他用#pragma warning将其关闭。 你也可以这样做。 或者你可以使用段user而不是段lib :你的字符串将仍然是在你的应用程序代码运行之前构建的。 段lib是真正用于像…哦,Qt或MFC或类似的框架,需要在任何应用程序代码运行之前进行初始化,包括在user初始化的东西。

以下是更多信息:

假设你有一个自己的应用程序库。 而且它有一些东西需要在任何代码运行之前被初始化,因为这个库暴露的某些类意图被(或者被允许)静态地分配到你的应用程序代码中,而这些类会做复杂的事情在他们的构造函数中需要一些预先计算的(但不是静态的)数据。 所以对于那些预先计算好的东西,你需要在一个类的构造函数(一个不同的类)中进行预先计算,然后静态分配这个类的一个实例,以便该实例的初始化调用它的预先计算所有东西的构造函数,使用pragma init_seg(user)标记。 现在,在任何应用程序代码运行之前(包括代码中此库类的静态实例的所有构造函数),库的init_seg(user)代码都将运行,因此,当您构建此库类的静态实例时他们需要的数据将在那里。

现在考虑一些真正需要在那里的东西,其中存在可以调用的静态实例。 例如, std::cout 。 你可以在你自己的类的构造函数中调用std::cout方法, 显然, std::cout对象需要在任何代码运行之前初始化。 而你的一些代码可能会运行在标记为init_seg(user)东西上。 所以微软在init_seg(compiler)放置了所有这些代码 – 也就是std::cout等的构造函数。 那些东西将在别的之前运行。

那么init_seg(lib)是什么? 那么,假设你是一个像MFC一样的框架。 你公开了像Application对象这样的东西,用户将(很可能,预计将)创建一个静态实例。 应用程序中的一些代码将在静态初始化时运行,这取决于MFC中需要初始化的其他东西。 所以显然它需要是init_seg ,但是在哪里? compiler是单独编译器和运行时,而你的框架材料(MFC)可能在用户被允许使用的init_seg(user)中使用…所以你得到了compileruser之间的中间级别 – 这是lib

现在很少需要类似的东西,因为程序使用的大多数C ++库本身并不被多个库所使用,因此不需要确保它们在所有其他“普通”库之前被初始化。 MFC可以,因为你可能已经从一个或多个供应商那里购买了第三方的MFC控件或其他库,而那些依赖于MFC的MFC可能会在构造函数中使用MFC,并且可能会静态地使用这些库中的对象,所以MFC需要在其他图书馆之前进行初始化。

但在大多数情况下, 您的库不会成为人们正在使用的其他 C ++库的依赖项。 因此,没有任何类型的依赖链,你的库需要在其他库之前初始化。 你的库可能需要在用户代码之前初始化,是的,但是没有任何需要初始化的顺序。 所以init_seg(user)对他们都是好的。

而且,微软(以及大多数C ++专家)会告诉你:如果在你的应用程序的静态初始化的时候 ,你需要初始化你的单独的库,那么你做错了。 认真。 那里有一个设计问题。

所以,要回应一个评论:这不是一个编译器错误。 这是用户警告。 相当良性:如果你忽略它,没有什么会出错的(不像忽略了从long到int的警告)。 但是,如果你正在使用init_seg(lib)你可能不会真正理解那个编译器特性是什么,所以他们希望你考虑一下。 想过之后,如果你仍然想这样做,那么请关掉警报。