【问题标题】:Undefined behavior and temporaries未定义的行为和临时性
【发布时间】:2015-11-18 20:49:09
【问题描述】:

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;
}

【问题讨论】:

  • @wendelbsilva,知道问题的历史,我可以告诉你,OP 需要一些东西来证实你的陈述;)
  • 1 和 2 应该没问题 - 我不知道它们违反了任何规则,尽管很难证明是否定的。 3 对于 [dcl.ref]/5 更棘手(“应初始化引用以引用有效的对象或函数。”),但该语言显然是有缺陷的(它需要诊断,这显然是不可能的),所以应该发生什么还不清楚。
  • @DavidSchwartz 不,这对于指针来说并非完全没问题。您的第三个问题的指针等效项具有 UB。 (至少在 C 中肯定如此,我高度怀疑 C++ 并没有改变这一点。)
  • 此代码不返回对临时的引用。它返回对对象 i 的引用。
  • @Lao 这取决于您是指“有效代码”是“不会在我的系统上崩溃的代码”还是“遵循 C++ 规范定义的规则的代码”。正如您所建议的那样,前者是您只需尝试即可回答的问题,但这个问题是关于后者的。

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


【解决方案1】:

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

没有。引用必须引用有效对象的规则在引用被初始化时适用。 cmets 中已经引用了该规则:“应初始化引用以引用有效的对象或函数。”您的程序中没有违反此规则,并且在引用方面没有其他限制要求它们在初始化后引用有效的对象或函数。

该标准有一些涉及悬空引用的示例,例如 [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 未初始化为引用有效的对象或函数。从问题的 cmets 可以看出,标准中的措辞存在问题,但这条规则的意图很明显,如果违反它,行为是未定义的。

【讨论】:

    【解决方案2】:

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

    C++ 标准草案中我们真正拥有的全部来自8.3.2 部分[dcl.ref]

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

    这不适用于情况 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 请解释我的回答有什么问题
    猜你喜欢
    • 2018-08-22
    • 2020-09-16
    • 2021-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-18
    相关资源
    最近更新 更多