未定义的行为和临时性

Dav*_*rtz 14 c++ undefined-behavior language-lawyer temporary-objects

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

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

int main()
{
    func();

    cout << "good" << endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

2)仅仅具有对不再存在的对象的引用是不确定的行为,即使该引用未被使用?例如,该程序是否保证输出"良好":

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

    cout << "good" << endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

3)结合这些是不确定的行为?

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

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

    cout << "good" << endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

小智 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.
Run Code Online (Sandbox Code Playgroud)

并且没有说任何这样的例子,仅仅存在悬空参考是无效的.虽然它从未被明确表示为允许,但没有任何禁止它的规则就足以允许它.

1)返回对临时的引用是否是未定义的行为,即使该引用未被使用?

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

3)结合这些是不确定的行为?

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


Sha*_*our 5

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

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

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

这不适用于案例1,因为我们没有初始化引用,也没有案例2,因为在初始化引用时对象是有效的.

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

如果我们查看缺陷报告453:引用可能只绑定到"有效"对象,它处理绑定对无效对象的引用的含义.目前提出的决议案如下:

[...]如果引用直接绑定到的左值既不指定现有对象或适当类型的函数(8.5.3 [dcl.init.ref]),也不指定适当大小和对齐的存储区域.包含引用类型的对象(1.8 [intro.object],3.8 [basic.life],3.9 [basic.types]),行为未定义.[...]

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