问题描述
鉴于从另一个类的静态成员变量初始化的静态成员变量,非文字的 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};
最简单的解决方案是以正确的顺序在同一翻译单元中定义两个对象。更为通用的解决方案是使用
C++ standard draft [basic.start.static]
这篇关于C ++:使用int vs struct静态依赖于静态成员变量的初始化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!