假设我在C ++中有这个类:
class A
{
public:
static const TDouble pi_d;
static const TDouble pi;
static const TDouble div;
};
它们按以下方式在.h文件中初始化:
const TDouble A::pi_d = 3.14;
const TDouble A::pi = A::pi_d;
const TDouble A::div = A::pi / 180.0;
当我打印成员div时,结果为0.0000。 如果我改变这一行:
const TDouble A::pi = A::pi_d;
这一行:
const TDouble A::pi = 3.14;
然后一切正常,打印出正确的值。
你知道这是什么原因吗?
感谢您的时间。 阿萨夫。
答案 0 :(得分:7)
关于“静态初始化顺序”的答案对于在不同翻译单元中定义但在同一TU内定义的对象是正确的:
9.4.2 / 7:
静态数据成员的初始化和销毁与非本地对象(3.6.2,3.6.3)完全相同。
3.6.2 / 1:
具有静态存储持续时间的对象在同一转换中的命名空间作用域中定义 单位和动态初始化应按其定义出现在的顺序初始化 翻译单位。
您的定义是正确排序的,因此应按正确的顺序初始化它们。我会接受AProgrammer关于多个定义的评论。与非成员const对象不同,您的对象具有外部链接:
3.5 / 5:
另外,一个成员函数,静态数据成员,类范围的类或枚举都有外部链接 如果类的名称有外部链接。
如果头文件包含在多个翻译单元中,那么代码违反了ODR,我猜测得到的未定义行为是初始化的直线性。尝试将静态成员的定义放入单个源文件中,看看会发生什么。
答案 1 :(得分:2)
标准3.6.2表示这样的初始化应该有效,做了一些假设。
“具有使用常量表达式(5.19)初始化的静态存储持续时间的POD类型(3.9)的对象应在进行任何动态初始化之前进行初始化。”因此,3.14的赋值应该在任何其他初始化之前发生。
“在同一翻译单元中命名空间范围内定义并动态初始化的静态存储持续时间的对象应按其定义在翻译单元中出现的顺序进行初始化。”由于pi
出现在定义中div
之前,因此应首先对其进行初始化。
我假设这些陈述与你给出的一样,TDouble
是double
的某种奇特版本。如果TDouble
是具有真实行为的类,则会使事情变得复杂。类似地,您没有显示代码的上下文,甚至不显示.h文件在多个.c文件中是#include
d(在这种情况下,您会遇到单一定义规则的问题)。或者,您可能没有使用符合标准的编译器。
那么,TDouble
的定义是什么?线条的背景是什么?你使用什么编译器,以及使用哪些编译器选项?
像这样的初始化并不是一种好的风格,部分原因是代码中的微小变化或者你如何使用它会导致错误,但这应该是我能说的。
答案 2 :(得分:1)
除非您向我们提供有关TDouble类型究竟是什么的更多信息,否则无法回答此问题。
我从样本中猜测,TDouble有一个有损转换错误,或者没有正确实现/
运算符(在分割之前基本上转换为int)。但这只是猜测,除非我们看到这种类型。
答案 3 :(得分:0)
未定义静态成员的初始化顺序。依靠一个静态成员初始化另一个静态成员不能可靠地工作。你不太可能真的需要两个不变的静态成员,所以我只想说消除一个。
当然,您的实际代码可能会有更微妙的内容。请记住,您不能指望常量初始化的顺序,而不能依赖于构造函数初始化列表中字段初始化的顺序,并相应地编写代码。偶尔的宏可以提供帮助。
#define PI 3.14
const TDouble A::pi_d = PI;
const TDouble A::pi = PI;
const TDouble A::div = PI / 180.0;
这是有效的,因为宏是文本替换,并且不能像静态成员初始化那样重新排序。