为啥我不能将 const 左值引用绑定到返回 T&& 的函数?

Posted

技术标签:

【中文标题】为啥我不能将 const 左值引用绑定到返回 T&& 的函数?【英文标题】:Why can't I bind a const lvalue reference to a function returning T&&?为什么我不能将 const 左值引用绑定到返回 T&& 的函数? 【发布时间】:2018-07-04 12:53:30 【问题描述】:

我正在将函数的某些返回值绑定到 const 左值引用,但在 const 左值引用的生命周期结束之前,该对象已被删除。

在以下示例中,Foo 对象在 foo 的生命周期结束之前被销毁:

#include <iostream>
#include <string>

struct Foo

    ~Foo()
    
        std::cout << "Foo destroyed: " << name << std::endl;
    
    std::string name;
;

Foo&& pass_through(Foo&& foo)

    return std::move(foo);


int main()

    const Foo& foo = pass_through("some string");
    std::cout << "before scope end" << std::endl;

输出是:

Foo 被破坏:一些字符串 在范围结束之前

住在科里鲁:1

我认为你可以将const T&amp; 绑定到任何东西。返回T&amp;&amp; 是不好的做法吗?应该首选按值返回吗?

我在这里的 cpprestsdk 中偶然发现了这个:

inline utility::string_t&& to_string_t(std::string &&s)  return std::move(s); 

https://github.com/Microsoft/cpprestsdk/blob/master/Release/include/cpprest/asyncrt_utils.h#L109

非常混乱,因为 to_string_t 的 windows 版本(由预处理器宏调度)按值返回

_ASYNCRTIMP utility::string_t __cdecl to_string_t(std::string &&s);

编辑: 为什么将pass_through 的结果传递给采用const Foo&amp; 的函数时会起作用?这种情况下寿命会延长吗?

【问题讨论】:

一大早来不及思考,但显式析构函数可能会阻止隐式创建移动构造函数。 en.cppreference.com/w/cpp/language/move_constructor 仅当引用直接绑定到临时对象时才适用生命周期延长。 @KennyOstrom 我尝试通过Foo(Foo&amp;&amp;) = default; 显式生成默认移动构造函数,它产生了相同的结果。 您可以将它作为参数传递,因为临时的生命周期持续到创建它的“完整表达式”结束。(非常非正式地,“直到下一个分号”。)没有扩展是必要的。 静态分析应该能够检测到这一点,我预测我们将来会看到编译器能够对此发出警告 【参考方案1】:

来自标准:

15.2 临时对象

6.9 A temporary object bound to a reference parameter in a function call persists 
    until the completion of the full-expression containing the call.

本质上它的意思是因为你传入了一个临时对象,然后没有延长它的生命周期(例如,通过将它移动到左值),那么它的生命周期只会持续到调用 @ 之后的第一个 ; 987654325@ 在您的代码中。在此之后,您将留下 foo 作为悬空引用。

int main()

    const Foo& foo = pass_through("some string"); // "some string" lifetime ends here
    std::cout << "before scope end" << std::endl;

至于返回右值引用是否是一种好习惯,我相信这两个答案已经详细介绍了该主题:

Should I return an rvalue reference parameter by rvalue reference?

Is returning by rvalue reference more efficient?

【讨论】:

以上是关于为啥我不能将 const 左值引用绑定到返回 T&& 的函数?的主要内容,如果未能解决你的问题,请参考以下文章

在 C++ 11 中将非 const 左值引用绑定到右值是不是有效?(修改)

为啥定义复制构造函数会给我错误:不能将'obj&'类型的非常量左值引用绑定到'obj'类型的右值?

对“const int *”类型的非 const 左值引用不能绑定到不相关类型“int *”的值

为啥我需要将默认引用参数定义为 const 以便我可以为其分配左值? [复制]

C++左值引用和右值引用

为啥非 const 引用必须用左值初始化?