【发布时间】:2015-07-01 13:00:44
【问题描述】:
以下代码的行为是否明确?
struct X { int i; }; // trivial
struct Y : X { Y(){} }; // non-trivial
extern X xobj;
int& r1 = xobj.i; // #1
X xobj;
extern Y yobj;
Y& r2 = yobj; // #2
// int& r3 = yobj.i; // #3 - this is UB according to the standard
Y yobj;
此代码的灵感来自 C++ 标准中的示例,即草案 N4140 [class.cdtor]/1。
那段是这样写的:
对于具有非平凡构造函数的对象,引用该对象的任何非静态成员或基类 在构造函数开始执行之前会导致未定义的行为。对于具有非平凡的对象 析构函数,在析构函数完成后引用对象的任何非静态成员或基类 执行会导致未定义的行为。
下面是一个例子,它展示了指针如何可以和不可以绑定到对象。
如此直观,#1 和 #2 似乎是定义明确的,而 #3 如果未注释则调用 UB,但是,首先,示例不规范,其次,示例中没有提及引用,并且第三,也是最重要的一点,上面的段落并不暗示否则行为是明确定义的。或者是吗?或者也许我错过了标准中的另一个相关引用?
编辑:如果对象具有静态存储持续时间,答案可能(可以说)是肯定的,但它们也可以是本地的,例如:
struct A { A(){} };
struct B { B(A&){} };
struct C {
B b;
A a;
C() : b(a) {}
};
int main() {
C c;
}
其实这是这个问题的最初灵感,见Circular dependency in constructor initialization list
【问题讨论】:
-
“引用任何非静态成员 [...] 会导致未定义的行为” - 引用正是引用的作用(因此得名)。
-
@molbdnilo 我明白这一点,但它没有解释会发生什么否则(例如,在构造函数开始为具有平凡构造函数的类之前引用...),这就是问题的重点。
-
“提到它”的意思是提到它(它是英文单词“refer”)。
-
相关:CWG issue 1530 和 [basic.life]/6
-
@AntonSavin 除非我误解了英语,否则特殊情况“对于具有非平凡构造函数的对象,[...]”暗示在其他情况下行为是明确定义的。
标签: c++ reference language-lawyer c++14