C++,在函数中采用 const lvalue 和 rvalue 引用
Posted
技术标签:
【中文标题】C++,在函数中采用 const lvalue 和 rvalue 引用【英文标题】:C++, take const lvalue and rvalue reference in a function 【发布时间】:2014-07-17 05:12:00 【问题描述】:我有一些方法需要让他们能够通过 const 左值(它将被复制到哪里)和右值引用(用于速度)来获取变量
struct Object
...
Object(Object&& o) ...
Object(const Object& o) ...
...
;
...
struct SomeClass
...
Object arr[7];
void copy(int pos,const Object& o) arr[pos] = o;
void copy(int pos,Object&& o) arr[pos] = o;
...
;
因此,SomeClass 中的两个复制方法是完全一样的。唯一的区别是,在一个 Object 中作为 const 传递,它将被复制,而在另一个 Object 中,作为 rvalue 引用传递以供快速复制使用。
这两种方法的代码完全一致。
现在,在上面的示例中并没有那么悲惨,但是,我有一些更大的方法,9-15 行左右。显然,解决方法是像在此处一样复制它们,但感觉不对。
如何复用复制方法的代码?
【问题讨论】:
你可以在函数中按值和std::move
它。
嗯,Object 类使用右值引用构造函数来“窃取”o 对象的成员变量,并且让给定的对象一无所有。而 const Object 构造函数不能修改对象,也不能窃取它的变量,所以它必须复制。
@Praetorian 这是个好主意。如果在不复制任何内容的情况下找不到其他方法,我可能会使用它。
【参考方案1】:
首先,您在这两种情况下都在进行复制分配:
void copy(int pos,const Object& o) arr[pos] = o;
void copy(int pos,Object&& o) arr[pos] = o;
如果它有名字,它就是一个左值。在第二个函数中,o
有一个名称,所以它是一个左值(尽管是一个右值引用)。你想要arr[pos] = std::move(o);
。
避免写两次copy
的常用方法是按值取o
并从中移出:
void copy(int pos, Object o) arr[pos] = std::move(o);
如果你传递一个左值,o
将被复制构造,然后移动分配到arr[pos]
。如果您传递一个右值,o
将被移动构造,然后进一步移动分配到数组中。所以你仍然避免在右值情况下复制,但在这两种情况下你都需要支付额外的移动。如果移动成本低到应有的水平,则不会产生太多额外开销。
但是,请注意,这不适用于不支持移动语义的旧类型。在这种情况下,此函数将复制您传递的内容,然后从中复制分配,而两个带引用的重载只会复制一份。
【讨论】:
那么,你建议用这个替换这两个?但是如果 SomeClass 的用户想在调用 copy 时自己使用 std::move 怎么办? sc.copy(0,std::move(tempobj));还是我没有正确理解你? 哦,好吧,我明白了,用这个变体构造了两次右值。我喜欢! @VanillaFace 如果你传递一个像std::move
这样的右值,那么o
将被移动构造然后移动到数组中。【参考方案2】:
通用引用和std::forward
让您实现完美转发。这是修改后的copy
:
template <typename T>
void copy(int pos, T&& o) arr[pos] = std::forward<T>(o);
如果您担心可能从其他类型隐式转换为Object
,您还可以在copy
的正文中添加static_assert
。如果将左值Object
传递给copy
,则T
将被推导出为Object&
。 std::forward<Object&>
返回一个引用。因此,将选择复制分配重载。如果你将一个右值Object
传递给copy
,T
将被推导出为Object
。 std::forward<Object&>
返回Object&&
。由于std::forward<Object>(o)
也是一个右值,因此将选择移动赋值运算符。
【讨论】:
完美!!我只是很难过采取另一个最佳答案并将其提供给您:(以上是关于C++,在函数中采用 const lvalue 和 rvalue 引用的主要内容,如果未能解决你的问题,请参考以下文章
C++之error: cannot bind non-const lvalue reference of type ‘myString&’ to an rvalue of type ‘mySt
const_cast((char * const)not lvalue?
在 RValue 对象上调用 LValue ref 限定成员函数
C++ lvalue,prvalue,xvalue,glvalue和rvalue详解(from cppreference)