【问题标题】:C++, take const lvalue and rvalue reference in a functionC++,在函数中采用 const lvalue 和 rvalue 引用
【发布时间】: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 这是个好主意。如果在不复制任何内容的情况下找不到其他方法,我可能会使用它。

标签: c++ rvalue-reference lvalue


【解决方案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) 也是一个右值,因此将选择移动赋值运算符。

【讨论】:

  • 完美!!我只是很难过采取另一个最佳答案并将其提供给您:(
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-09-12
  • 1970-01-01
  • 2016-08-20
  • 1970-01-01
  • 1970-01-01
  • 2021-09-17
  • 2017-10-31
相关资源
最近更新 更多