将常量引用绑定到右值引用

nor*_*nor 1 c++ rvalue-reference

我在下面有这个私有成员函数,(类模板的一部分,Heap):

template <typename Task, typename Priority>
const size_t& Heap<Task, Priority>::parent_of(const size_t& index) const
{
    // ** warning C4172: returning address of local variable or temporary
    return (this_index-1)/2;
}
Run Code Online (Sandbox Code Playgroud)

我从其他函数调用它,如下所示:

template <typename Task, typename Priority>
void Heap<Task, Priority>::bubble_up(const size_t&   start_index)
{
    ....
    if (priority_of(start_index) > priority_of((parent_of(start_index)))) 
    { 
        ... do work ...
        //call recursively the bubble_up
        bubble_up(parent_of(start_index));
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)

问题是,priority_of函数参数index在递归的第二次调用中被破坏或释放:

template <typename Task, typename Priority>
const Priority& Heap<Task, Priority>::priority_of(const size_t& index) const
{
    return vec.at(index).second;
}
Run Code Online (Sandbox Code Playgroud)

现在,VS 警告我我正在返回函数中局部变量或临时(右值)的地址,parent_of最后,这种行为是有道理的,因为当控制存在/从parent_of所有局部变量(包括释放的函数参数)返回时!

现在,当将函数更改为parent_of按值返回(而不是按 const ref)时,事情开始工作了!

我来自 C++98,(所以我不清楚所有的右值引用)问题是:我应该何时以及如何使用右值引用 ( &&) 来克服这个问题?我可以引用(包括更改它的值)这个由编译器分配的临时对象并返回对它的引用(用作返回值)吗?

cig*_*ien 5

如果您想根据返回表达式的值类别保留返回值的生命周期语义,则不能返回 a const&,甚至 a ,&&因为您将面临悬空引用的问题。

相反,您可以使用decltype(auto)for 返回类型来推断返回表达式的适当值类别:

template <typename Task, typename Priority>
decltype(auto) Heap<Task, Priority>::priority_of(const size_t& index) const
{
    decltype(auto) result = vec.at(index).second;
    return decltype(result)(result);
}
Run Code Online (Sandbox Code Playgroud)

现在返回类型将推导出正确的值类别,即 l 值引用的 l 值,pr 值(临时)和 x 值(到期值)的 r 值。

decltype(result)return 语句中的强制转换用于根据 id-expression 命名的实体的类型将表达式强制转换为适当的类型result

您需要对调用堆栈中要保留生命周期语义的所有函数使用此技术。

您可以将此技术视为完美转发,但方向相反,即向上调用堆栈,而不是向下。

这个答案基于这个有趣的闪电演讲中描述的技术。