10

在他的“Thinking in C++”(第 10 章)中,Eckel 描述了一种由 Jerry Schwarz 开创的用于解决惨败的技术。他说,如果我们想将x初始化为 100 并将y初始化为 200 并在所有翻译单元之间共享它们,我们将创建一个如下所示的 Initializer.h:

extern int x;
extern int y;
class Initializer {
   static int initCount;
   // if (initCount++ == 0) x = 100 & y = 200
   /* ... */
};
static Initializer init;

在实现文件中,我们有

#include "Initializer.h"
int x;
int y;
int Initializer::initCount;

并且 Eckel 说“静态初始化(在实现文件中)将强制所有这些值为零”。

让我考虑以下情况:编译器在包含该标头的某个其他文件之后处理实现文件(这意味着 x 和 y 在该其他文件中已设置为 100 和 200)。编译器看到int x了,那么它会做什么呢?它会将 x 和 y 设置为零,从而消除初始化和以前文件中所有可能的更改吗?但如果确实如此,那么initCount也将被设置为零,从而破坏整个技术。

4

5 回答 5

4

但是,如果它是真的,并且编译器在另一个文件之后处理实现文件,那么它会将 x 和 y 设置为零,从而消除初始化和以前文件中所有可能的更改?

我不确定你的意思。如果xy在其他文件中定义,那么您会遇到链接器冲突,并且程序根本无法编译。

如果以这种方式实现,最重要的是,程序中将有它们的唯一x实例yInitializer::initCount它们实际上是全局的,将0在程序开始时初始化,任何Initializer构造之前(由于包含声明static该类的实例的标头)。a 的每个构造都会首先检查是否由于etc构造了static Initializer任何其他s。Initializerif (initCount++ == 0)

因此,第一个Initializer运行的 ctor(仍然在 enter 之前main)将设置所有三个值。

于 2011-03-14T13:28:08.640 回答
3

“初始化程序”中所做的是赋值,而不是初始化(假设语法有效)。

因此,它为您的特殊情况“解决”了静态初始化顺序惨败,因为首先没有惨败。x 和 y 是整数,它们不会在不可预知的时间相互调用,最重要的是它们也存在于同一个翻译单元中。编译器只会正确初始化它们。如果您之后按定义的顺序分配值,那很好,但它只会更复杂,而不是更好。

要出现静态初始化顺序惨败,您需要这样的情况:x 的构造函数需要 y 的值(或相反),并且它们位于不同的翻译单元中。因此,这是否有效是 50:50 的机会。

现在,“Initializer”结构将按定义的顺序正确赋值,但那时,x 和 y 的构造函数已经运行,因为你不能分配给没有构造的东西......所以它不会完全避免这个问题,如果它存在的话。

首次使用时构建是处理此问题的常用方法。该技术有不同的风格(每种都有自己的优点和缺点),例如:

x& get_x() { static x *xxx = new x(); return *xxx; }
于 2011-03-14T13:48:23.340 回答
2

假设您的意思是在其他源文件中的静态初始化范围内任何可能的使用和初始化,那么您是绝对正确的:如果编译器决定在其他文件中运行此文件的静态初始化,那么您将撤消其他工作。

在许多情况下,您可以通过根本不使用全局/静态来为自己省去很多麻烦。

于 2011-03-14T13:44:15.767 回答
1

The global x and y will be initialized to zero when the program is loaded, before any code was executed. When any Initializer is created, x and y are already initialized to zero. Things happen in that order:

  1. Program is loaded
  2. Global and static variables are zero initialized (x and y get their 0 values)
  3. Global objects are constructed (the Initializer sets x and y to 100 and 200)
于 2011-03-14T13:29:23.713 回答
0

为什么不声明(在文件范围内,在单个翻译单元中):

int x = 100;
int y = 200;

x 和 y 将存储在图像的读/写部分中,因此它们在进程中的任何代码执行之前被初始化。您无需担心普通旧数据的初始化顺序。

于 2012-09-20T18:08:30.097 回答