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&amp;std::forward&lt;Object&amp;&gt; 返回一个引用。因此,将选择复制分配重载。如果你将一个右值Object 传递给copyT 将被推导出为Objectstd::forward&lt;Object&amp;&gt; 返回Object&amp;&amp;。由于std::forward&lt;Object&gt;(o) 也是一个右值,因此将选择移动赋值运算符。

【讨论】:

完美!!我只是很难过采取另一个最佳答案并将其提供给您:(

以上是关于C++,在函数中采用 const lvalue 和 rvalue 引用的主要内容,如果未能解决你的问题,请参考以下文章

C++之error: cannot bind non-const lvalue reference of type ‘myString&’ to an rvalue of type ‘mySt

C++特殊成员

const_cast((char * const)not lvalue?

在 RValue 对象上调用 LValue ref 限定成员函数

C++ lvalue,prvalue,xvalue,glvalue和rvalue详解(from cppreference)

12.2 C++常对象成员