在 C++ 中将右值引用转换为临时参数到 const 左值返回的正确方法

Posted

技术标签:

【中文标题】在 C++ 中将右值引用转换为临时参数到 const 左值返回的正确方法【英文标题】:Correct way to convert rvalue reference to temporary parameter to const lvalue return in C++ 【发布时间】:2020-08-24 14:59:28 【问题描述】:

我正在尝试实现类似 find 的方法来从容器中提取对值的引用,并在未找到该值或该值的类型不兼容时返回默认值。

template<class T> const T& get (key_type k, const T& def)

    const T* r = dynamic_cast<const T*> (find(k)); // suppose `find` returns a pointer to common base class or NULL if the key not found
    return r ? *r : def; 

如果def 是临时对象,则此函数无法正常工作:

const sometype& val = find(key, sometype(someargs));

那么,是否可以使用右值引用并以某种方式移动或复制临时对象来处理这种情况?

template<class T> const T& get (key_type k, T&& def)

    const T* r = dynamic_cast<const T*> (find(k)); // suppose `find` returns a pointer to common base class or NULL if the key not found
    return r ? *r : std::move(def); // or copy? or something else?

T也可能是一个抽象基类。而且,拜托,我更喜欢无升压的解决方案。

【问题讨论】:

你有什么理由不像标准库那样做并返回一个迭代器?然后调用代码可以检查迭代器,如果它不等于 end 迭代器,那么它是有效的间接通过。 @NathanOliver,对项目的这种检查会有很多重复,所以寻找一种方法将重复代码形成为子程序。 如果您想允许临时人员,我怀疑您能否避免这种情况。临时生命周期延长不通过函数,因此无法从传递给函数的右值中获取左值。您可以禁止右值,但不确定这是否可以接受。 如果有办法,那将是从函数中返回内容的默认方法,也是唯一的方法,你觉得呢?太方便了,直接返回引用,不用考虑生命周期! get (key_type k, T&amp;&amp; def) = delete; 会很糟糕,因为它还会阻止您接收左值(感谢参考折叠规则)。我认为get (key_type k, const T&amp;&amp; def) = delete; 应该可以工作。 【参考方案1】:

不,你不能。临时对象仅对该语句有效,并且在您通过返回的引用访问它之前将被销毁。

const sometype &val = get(not_existing_key, get_temporary_object());
do_something_with(val);

当你do_something_with(val)时,引用val绑定的对象已经被销毁了。 不应使用参数def 的临时对象调用get 函数。 相反,您可以将临时对象复制到变量中,然后使用对变量的引用调用函数。

auto copied_object = get_temporary_object();
const sometype &val = get(not_existing_key, copied_object);
do_something_with(val);

现在,val 绑定的对象在变量copied_object 中。

【讨论】:

我想 C++ 不会理解像 get(not_existing_key, (auto copied_object = get_temporary_object)); 这样的东西?可能你的答案应该是...get(not_existing_key, copied_object)?无论如何,我不完全理解 std::movestd::copy 到底做了什么来反对...

以上是关于在 C++ 中将右值引用转换为临时参数到 const 左值返回的正确方法的主要内容,如果未能解决你的问题,请参考以下文章

右值引用,移动语义,完美转发

如何评价 C++11 的右值引用(Rvalue reference)特性?

C11新特性右值引用&&

重新理解C11的右值引用

对临时声明的右值引用

c++11的右值引用移动语义