【问题标题】:return const reference vs temporary object返回 const 引用 vs 临时对象
【发布时间】:2016-02-12 16:52:16
【问题描述】:

我想知道为什么返回本地对象的 const reference 是非法的,而返回 local object 是合法的,只要将其分配给 const reference

vector<int> f_legal() {
    vector<int> tempVec;
    tempVec.push_back(1);
    return tempVec;
}

const vector<int>& f_illegal() {
    vector<int> tempVec;
    tempVec.push_back(1);
    return tempVec;
}

void g() {
    const vector<int>& v1 = f_legal(); // legal
    const vector<int>& v2 = f_illegal(); // illegal
}

编辑: 我的观点是,如果将 const ref 分配给返回的局部变量是合法的,那么将 const ref 分配给返回的局部变量的 const ref 也不应该是合法的吗?

【问题讨论】:

  • @Ed Heal 是的,在 C++ 中明确定义了本地 const 引用将延长它所绑定的临时对象的生命周期。
  • @EdHeal 是的,这是合法的。标准中有一个特殊情况,只要在当前范围内有对它的 const 引用,本地对象就会保持活动状态。

标签: c++ reference constants


【解决方案1】:

即使您将其分配给 const 引用,返回值也被声明为按值传递,这意味着它将作为临时对象复制[1] 到外部,然后绑定到 const 参考。将临时对象绑定到 const 引用是可以的,直到超出 const 引用的生命周期,对象才会被销毁。

另一方面,返回局部变量的引用是非法的。当函数返回时,局部变量会被销毁,这意味着外部引用将被悬空。

编辑

我的观点是,如果将 const ref 分配给返回的局部变量是合法的,那么不应该将 const ref 分配给返回的局部变量的 const ref 也是合法的吗?

要点是第一种情况不是将 const ref 分配给返回的 局部变量,而是将 const ref 分配给返回的 临时变量。 (可能从局部变量中复制。)


[1] 从技术上讲,根据 RVO,副本可能会被省略。

【讨论】:

  • 你确定总是这样吗?甚至考虑RVO/NRVO
  • @JamesAdkison:会有一个临时对象,并且引用将绑定到该临时对象。副本可能会被省略(如果结果可以直接在临时中构造)。
  • @BenVoigt 是的,这就是我的观点(即可以省略副本)。
  • @JamesAdkison afaik RVO 作为优化不会改变任何规则。 “规则”是:返回值按值传递(即复制)
  • 问题不就是为什么会这样吗?
【解决方案2】:

返回对局部变量的引用是非法的(未定义行为)。时期。没有constmutable 子句。

这是因为局部函数变量具有自动存储期限。它们在函数退出后被“销毁”。如果函数返回对此类变量的引用,则称该引用是悬空的:它引用了一个不再存在的对象。

第一个是合法的,因为有一条特殊的 C++ 规则:初始化对 prvalue 的引用会将临时对象的生命周期延长到引用的生命周期。

【讨论】:

  • 该规则实际上与const 无关——任何直接绑定到临时的引用都会延长该临时的生命周期。在 C++98 中,其他规则规定只有 const 引用可以直接绑定到临时对象,这些规则现在已经改变,这对生命周期扩展规则产生了多米诺骨牌效应。
  • @BenVoigt 这是我第一次听说这个。可以提供参考吗?
  • @BenVoigt 谢谢。这是最有帮助的。
  • @Maggyero:这不是直接绑定到临时的引用,而是编译错误。但是int&amp;&amp; r = 3; 确实可以编译,并且确实延长了临时文件的生命周期。
  • @Maggyero:您还可以从类型不匹配或其他限定符不匹配中获取引用绑定编译错误,例如尝试在没有const_cast 的情况下删除 volatile。如果我说一个引用直接绑定的,那么自然必须遵循我只是在谈论可能的场景。
【解决方案3】:

很可能是因为它会完全破坏整个基于堆栈的调用约定,这些约定已经为我们服务了几十年……几乎每个 CPU 都假定。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-07-18
    • 2023-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-02
    • 2010-10-20
    相关资源
    最近更新 更多