【问题标题】:Assign a value to an rvalue reference returned from function为从函数返回的右值引用赋值
【发布时间】:2020-09-21 17:51:01
【问题描述】:
#include <utility>
template <typename Container>
decltype(auto) index(Container &&arr, int n) {
    return std::forward<Container>(arr)[n];
}

进行函数调用:

#include <vector>
index(std::vector {1, 2, 3, 4, 5}, 2) = 0;

当函数调用完成时,对象std::vector {1, 2, 3, 4, 5} 将被销毁,将值分配给已释放的地址会导致未定义的行为。但是上面的代码运行良好,valgrind 什么也没检测到。也许编译可以帮助我制作另一个不可见的变量,例如

auto &&invisible_value {index(std::vector {1, 2, 3, 4, 5}, 2)};
invisible_value = 9;

如果我的猜测不正确,我想知道为什么将值分配给从函数返回的右值引用是有效的,以及临时对象 index(std::vector {1, 2, 3, 4, 5}, 2) 何时会被销毁。

这个想法源于《Effective Modern C++》,Item3:了解decltype

【问题讨论】:

  • 如果您无法在不存储函数的情况下访问函数的返回值,您如何想象函数链的工作原理?在这种情况下,您返回右值引用的事实并不真正相关。右值引用也是左值。

标签: c++ c++11 c++14 rvalue-reference rvalue


【解决方案1】:

invisible_value = 9; 是完全合法的赋值,因为 9 确实是临时的。右值引用可以分配一个临时的但不绑定到左值(例如一个变量;但你可以像下面这样实现:

int a =10;
invisible_value=std::move(a);

https://godbolt.org/z/iTNGFr。模式详解在本题C++ Double Address Operator? (&&)

编辑:

只有在相同范围内的赋值才是合法的。 invisible_value 在这种情况下是指在索引函数范围内的东西,如果你有它的引用,它的行为是未定义的。

【讨论】:

  • 不,这是错误的。在invisible_value 的情况下,向量在invisible_value 初始化后被销毁,它是一个悬空引用。 invisible_value = anything; 那时是 UB。
  • 是的!你说的对。我的错。只有在同一范围内,上述观点才有效。 invisible_value case 是来自函数的引用,它的作用域/生命周期在函数中结束。
【解决方案2】:

您说“当函数调用完成时,对象向量 {1, 2, 3, 4, 5} 将被销毁”,但这是不正确的。为函数调用创建的临时文件在语句结束之前不会被删除,即下一行代码。否则想象一下通过临时字符串的 c_str() 会破坏多少代码。

【讨论】:

  • 对此不太确定,您有任何消息来源吗?这个向量实际上并没有返回,而是传递给了一个函数,所以当index返回时它应该被销毁。相反,我认为正在发生的是元素n 的副本作为右值引用返回,它将一直存在到调用范围结束,因此可以分配另一个值。但是,我在这里也可能是错的。 :-)
  • @Carsten “所有临时对象都被销毁,作为评估(词法上)包含它们被创建的点的完整表达式的最后一步” Source跨度>
  • @Carsten 当然是指临时工。我们谈论的是临时工的寿命。我粘贴的引用表明临时对象在评估它们出现的完整表达式的最后一步被销毁。这清楚地表明 vector 临时存在直到分配给函数返回的引用之后。问题是分配发生时vector 是否仍然存在,因为如果不存在,代码将调用 UB。答案是:是的,它确实存在,因为在赋值发生之前,尚未计算完整表达式。
  • @Evg 是的。现在由实现定义 arr 在分配发生时是否已被销毁,这意味着分配成功或调用 UB。
  • @Carsten 另外,您粘贴的报价实际上与我粘贴的报价一致,并且与您声称表达式以 return 语句结尾的说法相矛盾。创建临时的完整表达式是index(vector {1, 2, 3, 4, 5}, 2) = 0;,所以 this 是保证临时的完整表达式。 index() 中发生的任何事情都与这一点无关。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-29
  • 1970-01-01
  • 2022-01-16
  • 2012-06-16
  • 2020-11-27
相关资源
最近更新 更多