C ++:使用int vs struct静态依赖于静态成员变量的初始化 [英] C++: static on static member variable dependent initialization with int vs struct

查看:144
本文介绍了C ++:使用int vs struct静态依赖于静态成员变量的初始化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

鉴于从另一个类的静态成员变量初始化的静态成员变量,非文字的 struct ii 有时会默认初始化到 0 333 。这取决于编译或链接顺序。 伪代码演示:

Given a static member variable which is initialized from a static member variable of another class, the non-literal struct ii is sometimes default initialized to 0 or to 333. This depends on the compilation or linking order. Pseudocode to demonstrate:

class StaticClass: // file 'ONE.cpp/.hpp'
    static int i = 2
    static struct ii { int a = 333 }

class ABC: // file 'abc.cpp'
    static int abc_i = StaticClass::i   // always 2
    static struct abc_ii = StaticClass::ii // sometimes 0, sometimes 333

调用 g ++ -std = c ++ 11 abc.cpp ONE.cpp&& ./a.out 导致 i = 2 / ii = 0 (gcc 4.8.1,与clang ++ 3.7相同; -Wall -Wextra 永不抱怨)。

Calling g++ -std=c++11 abc.cpp ONE.cpp && ./a.out results in i = 2 / ii = 0 (gcc 4.8.1, same with clang++ 3.7; -Wall -Wextra never complain).

但调用 g ++ -std = c ++ 11 ONE.cpp abc.cpp&& ./a.out 导致 i = 2 / ii = 333

ONE.o abc.o abc.o ONE.o 的情况相同以及以一种或另一种方式串联文件时:

The same happens with ONE.o abc.o vs abc.o ONE.o and also when concatenating the files one way or another:

cat ONE.cpp abc.cpp> X.cpp&& g ++ X.cpp&& ./a.out
cat abc.cpp ONE.cpp> Y.cpp&& g ++ Y.cpp&& ./a.out

在单个文件中删除包含内容并移动代码,如果存在此顺序,则默认初始化为0:

Removing includes and moving code around in the single file, the default initialization to 0 happens when this order is present:

const OneI ABC :: def_ii = StaticClass :: ii; const OneI StaticClass :: ii = OneI {333};

以及333的顺序:

const OneI StaticClass :: ii = OneI {333}; const OneI ABC :: def_ii = StaticClass :: ii;

为什么使用两个单独的编译单元也会发生这种情况?可以通过始终执行后一种命令来避免这种情况吗?在 ABC StaticClass :: ii 的静态指针中是否安全(我不想这么做)?

Why does this even happen with two separate compilation units? Can this be avoided somehow by enforcing the latter ordering all the time? Is using a static pointer in ABC to StaticClass::ii safe (I'd prefer not to, though)?

全C ++代码:

/* File: abc.cpp */

#include <iostream>
#include "ONE.hpp"

struct ABC {
  ABC();

  static const int def_i;
  static const OneI def_ii;
  void arg_i(const int &x) { std::cout << "i = " << x << " ";};
  void arg_ii(const OneI &x) { std::cout << "/ ii = " << x.a << " ";};

};

ABC::ABC() {
  arg_i(def_i);
  arg_ii(def_ii);
}

const int ABC::def_i = StaticClass::i;
const OneI ABC::def_ii = StaticClass::ii;

int main() {
  ABC a;
  std::cout << '\n';
}
/* End: abc.cpp */







/* File: ONE.cpp */

#include <iostream>

#include "ONE.hpp"

const int StaticClass::i = 2;
const OneI StaticClass::ii = OneI{333};

/* End: ONE.cpp */







/* File: ONE.hpp */

#include <iostream>

#ifndef One
#define One

struct OneI {
  OneI(int a_) : a(a_) { }
  int a;
};

struct StaticClass {
  const static int i;
  const static OneI ii;
};

#endif // One header guard

/* End: ONE.hpp */


推荐答案

恭喜!您遇到了静态初始化顺序惨败

未在多个转换单元中定义静态对象的初始化顺序。

The initialization order of static objects is not defined across multiple translation units.

StaticClass :: ii ONE.cpp 中定义,而 ABC :: def_ii 在<$ c $中定义c> abc.cpp 。因此 StaticClass :: ii 可能会或可能不会在 ABC :: def_ii 之前初始化。由于 ABC :: def_ii 的初始化使用 StaticClass :: ii 的值,因此该值取决于 StaticClass :: ii 尚未初始化

StaticClass::ii is defined in ONE.cpp and ABC::def_ii is defined in abc.cpp. Therefore StaticClass::ii may or may not be initialized before ABC::def_ii. Since the initialization of ABC::def_ii uses the value of StaticClass::ii the value will depend on whether StaticClass::ii was initialized yet.

静态对象在之内定义了翻译单位。对象按照定义的顺序初始化。因此,在串联源文件时,将定义初始化的顺序。但是,当您以错误的顺序连接文件时,定义的初始化顺序是错误的:

The initialization order of static objects within a translation unit is defined. Objects are initialized in the order in which they are defined. Therefore when you concatenate the source files, the order of initialization is defined. However, when you concatenate the files in the wrong order, the defined initialization order is wrong:

const OneI ABC::def_ii = StaticClass::ii; // StaticClass::ii wasn't initialized yet
const OneI StaticClass::ii = OneI{333};




可以通过始终强制执行后者的顺序来避免这种情况吗?

Can this be avoided somehow by enforcing the latter ordering all the time?

最简单的解决方案是以正确的顺序在同一翻译单元中定义两个对象。更为通用的解决方案是使用在首次使用惯用语言上构建。

Most trivial solution is to define both objects in the same translation unit, in the correct order. A more general solution is to initialize your static objects using Construct On First Use Idiom.


ABC 中使用静态指针指向 StaticClass :: ii 安全(不过我还是不想这么做)?

Is using a static pointer in ABC to StaticClass::ii safe (I'd prefer not to, though)?

在定义了指向对象的另一个转换单元中的静态对象初始化期间,不使用指针的解引用值,是的,将 ABC :: def_ii 替换为指针会很安全。

As long as the dereferenced value of the pointer isn't used during the initialization of a static object in another translation unit that where the pointed object is defined, yes, replacing ABC::def_ii with a pointer would be safe.

StaticClass :: ii 将在静态初始化阶段被††初始化为零。静态初始化顺序惨败涉及动态初始化阶段††

StaticClass::ii will have been zero-initialized during the static initialization phase††. The Static initialization order fiasco concerns the dynamic initialization phase††.

†† C ++标准草案 [basic.start.static]

†† C++ standard draft [basic.start.static]


如果不执行常量初始化,则将具有静态存储持续时间([basic.stc.static])或线程存储持续时间([basic.stc.thread])的变量初始化为零( [dcl.init])。零初始化和常量初始化合在一起称为静态初始化。所有其他初始化是动态初始化。静态初始化应在任何动态初始化发生之前执行。 [注意:非本地变量的动态初始化在[basic.start.dynamic]中进行了介绍;局部静态变量的变量在[stmt.dcl]中进行了描述。 —尾注]

If constant initialization is not performed, a variable with static storage duration ([basic.stc.static]) or thread storage duration ([basic.stc.thread]) is zero-initialized ([dcl.init]). Together, zero-initialization and constant initialization are called static initialization; all other initialization is dynamic initialization. Static initialization shall be performed before any dynamic initialization takes place. [ Note: The dynamic initialization of non-local variables is described in [basic.start.dynamic]; that of local static variables is described in [stmt.dcl]. — end note ]

这篇关于C ++:使用int vs struct静态依赖于静态成员变量的初始化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆