C++:对右值的常量引用

c++: const reference to an rvalue

本文关键字:常量 引用 C++      更新时间:2023-10-16
//old school '98 c++, no C++0x stuff
std::string getPath();
void doSomething()
{
    const std::string &path = getPath(); //const reference to an rvalue
    ... // doSomething with path
}
void doSomething2()
{
    const std::string path = getPath(); //regular variable
    ... // doSomething with path
}

doSomething和doSomething2之间有什么区别,哪一个是可取的?
在 doSomething 中使用对返回的 rvalue 的 const 引用是否安全?
doSomething2 是否创建了返回的 rvalue 的副本,编译器是否可以在此处进行 rvalue 优化?

在 doSomething 中使用对返回的 rvalue 的 const 引用是否安全?

是的,这完全没问题。该语言有一个特定的子句,该子句保证如果将引用绑定到右值,则会创建一个临时的,并且生存期将延长到创建引用的范围结束。

doSomething2 是否创建了返回的 rvalue 的副本,编译器是否可以在此处进行 rvalue 优化?

在这两种情况下,成本是相同的,因为编译器将执行RVO(返回值优化(

doSomething和doSomething2之间有什么区别,哪一个是可取的?

主要区别在于,在一种情况下,您为真实对象命名,而在另一种情况下,名称被赋予引用。编译器应在两个版本中生成完全相同的代码。

话虽如此,我发现使用const&具有误导性。它给人的印象是本地函数在某处引用了某个对象,但它实际上有一个副本(没有名称(。要意识到这是一个副本,维护者必须查看并验证正在调用的函数的签名。在值的情况下,行为更明显:函数维护函数返回的任何内容的副本(可能是值或引用(。

第二个区别是,法律上只允许您绑定 const 引用,这意味着该函数不能修改对象。在存储值的情况下,类型可以是非常量,函数可以修改该对象,因此该方法更灵活。

在 C++03 中,使用 const& trick 的唯一原因是,你知道函数返回一个值,你知道该类型派生自一个众所周知的基,并且你不想命名该类型 [看看 ScopeGuard]。在 C++11 中,这种使用不再重要,因为您只需使用 auto 让编译器自动找出类型即可。

(从其他评论来看,当您将引用绑定到有关其寿命的右值时,这似乎C++标准版本取决于保证人 - 这个答案反映了C++经典(

做某事有参考什么?

doSomething2 有一个可能不再存在的东西的副本,这很好

让我们看看getPath((:

通常,它将获取返回值,将其复制到堆栈,然后将其复制到LHS它可以直接分配给 LHS

它可以返回"hello",这将在堆栈上创建一个字符串 - 这不能被引用,因为它是临时的(doSomething的问题(

它可以返回一个静态的 const 字符串 - 在这种情况下,它可以完全内联并分配给 LHS

如果

std::string在函数getPath()内分配并在从该函数返回时销毁,则引用版本可能具有悬空引用。然后,这是危险的用法。

如果你有一个保存该字符串的类,并且该类的寿命超过了该const std::string &引用的范围MyClass::getPath(),那么在这种情况下,引用就不会悬而未决。

第二个版本将始终有效。