未定义行为和临时变量

14

1) 返回对临时对象的引用是否属于未定义的行为,即使该引用未被使用?例如,这个程序是否保证输出“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;
}

3
@wendelbsilva,了解问题的历史背景后,我可以告诉你,楼主需要一些证据来支持他/她的陈述 ;) - SergeyA
1
1和2应该是没问题的 - 我不知道它们违反了什么规则,虽然证明否定很困难。3更棘手,因为[dcl.ref]/5(“引用必须初始化为引用有效的对象或函数。”),但是这种语言显然有缺陷(它需要诊断,这显然是不可能的),所以应该发生什么是不清楚的。 - T.C.
1
@DavidSchwartz 不,指针并不完全适用。你第三个问题的指针等效物具有未定义行为。(至少在C语言中是这样的,我强烈怀疑C++也没有改变这一点。) - user743382
2
此代码不返回对临时对象的引用,而是返回对对象 i 的引用。 - M.M
1
@Lao 是的,确实已经明确说明了。这个问题并不是在问“这个程序会输出'good'吗?”,而是在问“这个程序是否有保证一定会输出'good'?”也就是说,是否符合C++定义的规则。 - user743382
显示剩余20条评论
2个回答

6

2) 即使这个引用没有被使用,仅仅拥有一个指向不存在的对象的引用是否是未定义行为?

不是的。当引用被初始化时,引用必须指向一个有效的对象,这是引用的规则。该规则已经在评论中被引用:“引用必须被初始化为指向有效的对象或函数。” 在您的程序中,没有违反此规则,并且在初始化后,没有其他限制要求引用引用有效的对象或函数。

标准中有一些涉及悬空引用的示例,例如[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) 即使不使用该引用,返回临时变量的引用是否属于未定义行为?

不是。结果的构建(引用的初始化)发生在调用函数的上下文中。甚至可以在调用函数中添加额外的代码,在结果的构建完成后运行本地对象的析构函数。由于引用被初始化为一个有效的对象,这就像你第二个问题一样,同样的规则仍未被违反。

3) 将它们组合起来是否属于未定义行为?

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


5
我没有看到任何禁止情况1和2的规则,也找不到相关的缺陷报告。
我们在C++标准草案中真正拥有的只有第8.3.2节[dcl.ref]:
引用必须被初始化为引用一个有效的对象或函数。[注意:特别是,空引用不能存在于定义良好的程序中,因为创建这样的引用的唯一方法是将其绑定到通过null指针间接引用获取的“对象”,这会导致未定义行为。...]
这不适用于情况1,因为我们没有初始化引用,对于情况2也是如此,因为当我们初始化引用时,对象是有效的。
但这似乎适用于情况3。那么有效对象的意思是什么呢?这是下面的缺陷报告讨论的主题。涵盖此主题的缺陷报告仍然处于开放状态,因此我们只能了解当前的想法,即这应该是未定义的行为。
如果我们看一下defect report 453: References may only bind to “valid” objects,它涉及将引用绑定到无效对象的含义。目前提出的解决方案是:
[...]如果一个左值直接绑定的引用既不指定适当类型的现有对象或函数(8.5.3 [dcl.init.ref]),也不指定适当大小和对齐方式的存储区域以包含引用类型的对象(1.8 [intro.object]、3.8 [basic.life]、3.9 [basic.types]),则行为未定义。[...]
因此,我们可以说当前的想法是这应该是未定义的行为,但当前这是一个缺陷报告,所以在这个缺陷报告被解决之前,我们不能确定。我会谨慎地假设它是未定义的行为。

@downvoter请解释一下我的回答有什么问题。 - Shafik Yaghmour

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接