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

Can I change static variable initialization order in C++?

本文关键字:初始化 变量 顺序 静态 我可以      更新时间:2023-10-16

i在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对象之前先初始化我的对象?

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

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

它看起来像一种简单的单顿类型,并在首次使用idiom 上调用。由于标准(C 11及以上),它可以保证一次初始化一次(甚至是原子!),并且在其C-tor内部,这样的对象可以访问其他"静态"变量,因此,如果没有圆形变量之间的依赖项,初始化的顺序将被严格定义。

有关其他信息,请参见此问题和此首先使用Idiom 的其他描述。

可能在这种情况下以某种方式可以帮助您:

确保非本地静态对象在首次使用之前初始化并仅在上次使用对象后被销毁。

它的动机非常明显:

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

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

stream.h

#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.cpp

#include "Stream.h"
#include <new>         // placement new
#include <type_traits> // aligned_storage
static int nifty_counter; // zero initialized at load time
static typename std::aligned_storage<sizeof (Stream), alignof (Stream)>::type
  stream_buf; // memory for the stream object
Stream& stream = reinterpret_cast<Stream&> (stream_buf);
Stream::Stream ()
{
  // initialize things
}
Stream::~Stream ()
{
  // clean-up
} 
StreamInitializer::StreamInitializer ()
{
  if (nifty_counter++ == 0) new (&stream) Stream (); // placement new
}
StreamInitializer::~StreamInitializer ()
{
  if (--nifty_counter == 0) (&stream)->~Stream ();
}

在流对象上调用任何成员函数之前,必须包括流类的标头文件。每个汇编单元中都包含了流媒体化合物类的实例。流对象的任何使用都遵循标头的包含,该对象确保在使用流对象之前调用初始化器对象的构造函数。

有关更多详细信息,请参见上面的链接。

编辑:我认为您需要的解决方案是使用另一个STL实现,如果您需要使用MSVC 2015并避免重新实现当前的内存管理黑客攻击(对不起,请称呼它,但这就是听起来像是什么,但是我又使用了一些自己的黑客来使用MSVC)。

我从未使用过开发环境中未包含的STL实现,但这是可能的。设置替代STL实现的包含路径和库路径应该是一个简单的问题。您可能会从尝试Stlport

开始

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

汇编单元(CPP文件)中的静态初始化顺序是发表声明的顺序。编译单元之间的静态初始化顺序是未定义的。请勿使用静态初始化来解决此问题。

看起来Rustyx将您指向正确的方向,他的评论链接到MSVC 中的覆盖记忆分配器。

编辑:看来您正在寻找的答案可能在这里:如何正确替换全局新&amp;删除操作员。请注意,这两个答案都是相关的,您将需要替换newdeletenew[]delete[]。由于这是在链接过程中应用的,因此显然Windows不会将其用于您加载的DLL(请参阅第一个答案的评论)。