【问题标题】:Lifetime of a class returned as const reference作为 const 引用返回的类的生命周期
【发布时间】:2021-05-12 00:34:11
【问题描述】:

如果我尝试从函数返回字符串文字,我可以制作以下两个版本:

std::string get_val()
{
    return "1234";
}

const std::string & get_ref()
{
    return "1234";
}

但是,让我感到困惑的是,我认为您需要一个长寿命的对象才能拥有一个左值引用(我将 const std::string & 读作左值引用,也许我弄错了)。

为什么会这样?从函数返回后"1234" 住在哪里?

【问题讨论】:

  • 我认为它不起作用,事实上 GCC 会对该代码发出警告,如果您尝试调用 get_ref() 它会崩溃 jdoodle.com/iembed/v0/90U
  • get_ref() 的第二版无效。它似乎可以工作,但返回对本地对象的引用仍然无效。
  • 您使用的是什么编译器和警告级别(或缺少警告级别),在哪些情况下未诊断?
  • 哦,废话,那是有道理的。问题是std::string & get_ref() 是编译器错误,但添加const 通过了构建,我没有注意到警告。我正在将 gcc 与 -Wextra 一起使用,但我只是感到困惑并过早发布到这里。对不起大家!
  • 它可能会“工作”,直到有东西覆盖了 std::string 的尸体,它正在分解临时字符串曾经所在的位置。似乎在工作是未定义行为的最狡猾的形式。

标签: c++ lvalue


【解决方案1】:
std::string get_val()
{
    return "1234";
}

在这种情况下,创建一个字符串类型的对象,然后调用移动构造函数(通常会说一个副本,但由于编译器优化,移动更可能被调用)以将值存储在目标变量中

const std::string & get_ref()
{
    return "1234";
}

在这里,您将返回一个对临时本地对象的引用,因此当字符串的构造函数完成使用“1234”构造字符串对象并调用返回时,该对象被销毁,因为创建的对象是临时的本地范围。它应该给你一个错误

【讨论】:

    【解决方案2】:

    第二个实现无效。

    实际上return "1234" 创建了一个临时(右值)字符串对象(好像它是return std::string("1234")),它驻留在堆栈上,并且一旦它返回返回的引用就变成了一个悬空引用,就像它在堆栈内存上一样.

    最近的编译器会发出如下警告:

    https://godbolt.org/z/hWM76n

    <source>: In function 'const string& get_ref()':
    <source>:5:12: warning: returning reference to temporary [-Wreturn-local-addr]
        5 |     return "1234";
          |            ^~~~~~
    

    【讨论】:

      猜你喜欢
      • 2019-12-18
      • 2023-03-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-12
      相关资源
      最近更新 更多