未定义的行为和临时行为

Undefined behavior and temporaries

1) return 对临时对象的引用是未定义的行为,即使未使用该引用?例如,这个程序是否保证输出 "good":

int& func()
{
    int i = 5;
    return i;
}

int main()
{
    func();

    cout << "good" << endl;
    return 0;
}

2) 简单地引用一个不再存在的对象是否是未定义的行为,即使该引用未被使用?例如,这个程序是否保证输出 "good":

int main()
{
    int *j = new int();
    int &k = *j;
    delete j;

    cout << "good" << endl;
    return 0;
}

3) 将这些组合起来是未定义的行为吗?

int& func()
{
    int i = 5;
    return i;
}

int main()
{
    int& p = func();

    cout << "good" << endl;
    return 0;
}

2) Is it undefined behavior to simply have a reference to an object that no longer exists, even if that reference is not used?

没有。当引用被初始化时,引用必须引用有效对象的规则适用。评论中已经引用了该规则:"A reference shall be initialized to refer to a valid object or function."您的程序中没有违反此规则,并且没有其他限制要求它们在初始化后引用有效对象或函数的引用。

该标准有一些涉及悬挂引用的示例,例如 [class.temporary]5.4:

struct S { int mi; const std::pair<int,int>& mp; };
S a { 1, {2,3} };
S* p = new S{ 1, {2,3} };  // Creates dangling reference.

并没有说任何这样的例子仅仅存在悬垂引用是无效的。尽管它从未明确声明是允许的,但没有任何禁止它的规则就足以允许它了。

1) Is it undefined behavior to return a reference to a temporary, even if that reference is not used?

没有。结果的构造(引用的初始化)发生在被调用函数的上下文中。在构造结果之后 运行s 的被调用函数中甚至可以有额外的代码:在构造结果完成之后 运行 局部对象的析构函数。由于引用被初始化为一个有效的对象,这就像你的第二个问题一样,仍然没有违反同样的规则。

3) Is it undefined behavior to combine these?

是的。在您的示例中, p 未初始化为引用有效的对象或函数。正如您从对问题的评论中可以看出的那样,标准中的措辞存在问题,但该规则的意图非常清楚,如果违反,则行为未定义。

我没有看到任何禁止情况 1 和 2 的规则,也找不到相关的缺陷报告。

我们真正从 C++ 标准草案中得到的全部来自 8.3.2 [dcl.ref]:

部分

[...]A reference shall be initialized to refer to a valid object or function. [ Note: in particular, a null reference cannot exist in a well-defined program, because the only way to create such a reference would be to bind it to the “object” obtained by indirection through a null pointer, which causes undefined behavior.[...]

不适用于情况 1,因为我们没有初始化引用,也不适用于情况 2,因为当我们初始化引用时对象是 有效

这似乎适用于案例 3。那么 valid object 是什么意思是以下缺陷报告的主题。涵盖该主题的缺陷报告仍然开放,因此我们只能对当前的想法有所了解,即这应该是未定义的行为。

如果我们看一下 defect report 453: References may only bind to “valid” objects ,它处理将引用绑定到无效对象的含义。当前提议的决议说:

[...]If an lvalue to which a reference is directly bound designates neither an existing object or function of an appropriate type (8.5.3 [dcl.init.ref]), nor a region of storage of suitable size and alignment to contain an object of the reference's type (1.8 [intro.object], 3.8 [basic.life], 3.9 [basic.types]), the behavior is undefined. [...]

所以我们可以说目前的想法是这应该是未定义的行为,但目前这是缺陷,因此在解决此缺陷报告之前我们不能确定。我会谨慎行事,并假设这是未定义的行为。