现代C++中临时寿命延长(Temporary Lifetime Extension)什么时候有用?

11

在C++中,您可以将函数的返回值(返回值而不是引用)绑定到const引用上,代码仍然有效,因为这个临时对象的生命周期将延长到作用域的末尾。例如:

std::string get_string() {
    return "abc";
}


void f() {
    const std::string& str = get_string();
    std::cout << str; // valid, str is not dangling reference.
}
我的问题是,什么时候它有用,例如代码什么时候像这样。
A get_a();
const A& a = get_a();

胜过代码

A get_a();
A a = get_a();

以什么方式(例如更快,更小的二进制大小等)? Aget_a 和调用 get_a 后代码实现应该是什么?

我手动测试了几个案例,在每种情况下似乎都有相同数量的复制和移动。

让我们限制这个问题到当前的C++标准、使用优化(O2,O3或其他编译器的等效选项)的现代编译器和版本。

1个回答

9
有意识地将prvalues的寿命延长到命名堆栈变量中,如果您知道确切的情况,则没有用处。这意味着,如果您不确定确切的情况,它就有用了。
比如,在模板函数中,用户应该给您一些具有“get”成员函数的对象,该函数返回符合某些预期行为的某些类型。问题是:get函数返回引用还是prvalue?
答案是:您不需要关心。返回prvalue或引用并不重要;重要的是它所返回的可以按照您的预期进行操作。因此,例如,您可能希望"obj.get() = 10"这样的代码能够正常工作。
也许get返回一个对象的引用。或者它返回一个prvalue,它是一个像引用一样的代理对象。在上述情况下,它可能有一个operator=重载,以便您可以对其进行赋值。您作为用户不需要关注这些细节。
那么,如果您想要(短暂地)存储get返回的内容怎么办?好吧,您不想执行"auto x = obj.get()",如果它返回一个实际的引用,您将获得引用的副本,这可能不是您想要的结果。因此,您可以执行"auto &&x = obj.get()"。寿命延长允许使用代理prvalue对象和实际引用一样工作。

不错的帖子。请原谅我的无知,但为什么获取引用的副本是一件坏事呢?它在哪些方面与原始引用的行为不同?我意识到 auto && 可以绑定到任何东西,因此更具适应性,但那并不是同一件事情。但也许我误解了,或者我只是在挑刺。在这里学到了关于 auto && 的一些有趣的东西。链接 - Paul Sanders
1
@PaulSanders:如果你期望能够执行obj.get() = 5;来给obj赋值,那么auto x = obj.get(); x = 5;是否会达到相同的效果?如果get的返回值是代理,则是的。如果get的返回值是语言引用,则不是。你可以使用auto&&来表示你想要存储get返回的内容。 - Nicol Bolas
好的,我还是不太理解这个问题,所以我写了一个demo,并且假设有int& get() { ... } ... auto x = obj.get();,你确实不能通过xobj进行赋值。但是为什么呢?在这里找到了答案:当自动推断类型时,它不会推断出引用类型,而总是推断出值类型。这就是关键短语。哎呀,使用这种语言一定要非常小心啊。 - Paul Sanders

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接