未定义的行为和临时性

时间:2015-11-18 20:49:09

标签: c++ language-lawyer undefined-behavior temporary-objects

1)返回对临时的引用是否是未定义的行为,即使未使用该引用?例如,该程序是否保证输出“好”:

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

int main()
{
    func();

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

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

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 个答案:

答案 0 :(得分:6)

  

2)是否未定义行为只是简单地引用一个不再存在的对象,即使该引用未被使用?

没有。当引用被初始化时,引用必须引用有效对象的规则适用。该规则已在评论中引用:&#34;引用应初始化为引用有效的对象或功能。&#34;在您的程序中没有违反此规则,并且在初始化后要求它们引用有效对象或函数的引用没有其他限制。

该标准有一些涉及悬空引用的例子,例如[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未初始化为引用有效对象或函数。从您对问题的评论中可以看出,标准中的措辞存在问题,但该规则的目的非常明确,如果违反该规则,则行为未定义。

答案 1 :(得分:5)

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

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

  

[...]引用应初始化为引用有效对象或   功能。 [注意:特别是,一个明确定义的程序中不能存在空引用,因为唯一的方法   创建这样的引用将是绑定到通过空指针间接获得的“对象”,   导致未定义的行为。[...]

不适用于案例1,因为我们没有初始化引用,因为当我们初始化引用时,对象有效,因此两者都没有。

这似乎适用于案例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]),行为未定义。 [...]

所以我们可以说当前的想法是,这应该是未定义的行为,但目前这是缺陷,所以我们不能肯定地说这个缺陷报告得到解决。我会谨慎行事并假设它是未定义的行为。