我可以在C ++中更改静态变量初始化顺序吗?

时间:2016-12-09 07:38:26

标签: c++ visual-studio visual-studio-2015 pragma static-variables

我在Visual Studio 2015 sp3中使用C ++。 由

#pragma init_seg(compiler)

,我首先初始化一些静态变量(到内存管理)。 https://msdn.microsoft.com/en-us/library/7977wcck.aspx

但是,有

#pragma init_seg(compiler)

在wcerr.cpp(Microsoft Visual Studio 14.0 \ VC \ crt \ src \ stl \ wcerr.cpp)中,所以这些对象在我的对象之前初始化。

我是否可以通过任何编译/链接选项强制我的对象在wcerr.cpp个对象之前被初始化?

4 个答案:

答案 0 :(得分:13)

其中一个解决方案是尝试将静态变量包装到静态函数中:

static type& My_static_obj() {
    static type my_static_obj_;
    return my_static_obj_;
}

它看起来像一个简单类型的Singleton并调用 Construct On First Use Idiom 。由于标准(C ++ 11及以上版本),它保证初始化一次(甚至原子化!),并且在其c-tor内部,这样的对象可以访问其他"静态"变量,因此,如果变量之间没有循环依赖关系,则将严格定义初始化顺序。

有关其他信息,请参阅this question以及此首次使用成语构建的其他说明。

答案 1 :(得分:3)

在这种情况下,nifty counter成语可能会以某种方式帮助你:

  

确保在首次使用之前初始化非本地静态对象,并且仅在最后一次使用该对象后将其销毁。

它的动机很明确:

  

当静态对象使用其他静态对象时,初始化问题变得更加复杂。如果静态对象具有非平凡的初始化,则必须在使用之前对其进行初始化。编译单元中静态对象的初始化顺序没有明确定义。跨多个编译单元的多个静态对象可能使用单个静态对象。因此,必须在使用前进行初始化。一个例子是std :: cout,它通常被许多其他静态对象使用。

直接复制并粘贴上述链接页面中的示例是值得的:

<强> Stream.h

library(purrr)

states <- state.abb[1:27]
agencies <- c("AID", "AMBC", "AMTRAK", "APHIS", "ATF", "BBG", "DOJ", "DOT",
              "BIA", "BLM", "BOP", "CBFO", "CBP", "CCR", "CEQ", "CFTC", "CIA",
              "CIS", "CMS", "CNS", "CO", "CPSC", "CRIM", "CRT", "CSB", "CSOSA",
              "DA", "DEA", "DHS", "DIA", "DNFSB", "DOC", "DOD", "DOE", "DOI")

walk(states, function(x) {
   map(x, ~sprintf("http://website.gov/%s_%s.zip", ., agencies)) %>% 
    flatten_chr() -> urls
    download.file(urls, basename(urls), method="libcurl")
}) 

<强> Stream.cpp

#ifndef STREAM_H
#define STREAM_H

struct Stream {
  Stream ();
  ~Stream ();
};
extern Stream& stream; // global stream object

static struct StreamInitializer {
  StreamInitializer ();
  ~StreamInitializer ();
} streamInitializer; // static initializer for every translation unit

#endif // STREAM_H
  

必须先包含Stream类的头文件,然后才能在Stream对象上调用任何成员函数。每个编译单元中都包含StreamInitializer类的实例。任何对Stream对象的使用都遵循包含标头,这确保在使用Stream对象之前调用初始化对象的构造函数。

有关详细信息,请参阅上面的链接。

答案 2 :(得分:1)

编辑:我认为你需要的解决方案就是使用另一个STL实现,如果你需要使用MSVC 2015并且还要避免重新实现你当前的内存管理黑客(很遗憾地称之为但是这听起来像是这样,但是又一次我使用了一些我自己的黑客来处理MSVC。)

我从未使用过未包含在开发环境中的STL实现,但它是可能的。将include和库路径设置为备用STL实现应该是一件简单的事情。您可以从尝试STLPort

开始

否则,在上次编辑之前,我对您的问题的原始建议是:

编译单元(cpp文件)中的静态初始化顺序是声明的顺序。编译单元之间的静态初始化顺序未定义。不要使用静态初始化来解决这个问题。

看起来RustyX指向正确的方向,他的评论链接到Overriding memory allocator in MSVC++

编辑:看起来您正在寻找的答案可能就在这里:How to properly replace global new & delete operators。请注意,这两个答案都是相关的,您需要替换newdeletenew[]delete[]。由于这是在链接期间应用的,显然Windows不会将这些用于您加载的DLL(请参阅第一个答案的注释)。

答案 3 :(得分:0)

您可以从Chromium项目Docs获得想法。请参阅“Singleton&amp; base :: LazyInstance”部分。