提供移动其参数的构造函数的惯用方法

时间:2017-08-31 15:15:53

标签: c++11 move-semantics rvalue-reference

假设我有以下课程:

#include <vector>
class Foo
{
public:
    Foo(const std::vector<int> & a, const std::vector<int> & b)
        : a{ a }, b{ b } {}
private:
    std::vector<int> a, b;
};

但是现在我想说明构造函数的调用者可能会将临时函数传递给它的情况,并且我希望将这些临时函数正确地移动到ab

现在我真的需要添加3个构造函数,其中1个作为右值引用有a,其中1个作为右值引用有b,只有rvalue引用参数有1个?

当然,这个问题可以推广到任何值得移动的参数,并且所需构造函数的数量是参数^ 2 2 ^ arguments。

这个问题也推广到所有功能。

这样做的惯用方法是什么?或者我完全错过了一些重要的东西?

2 个答案:

答案 0 :(得分:4)

通常的方法是按值传递,然后从参数中移动构造成员:

import {TabContentComponent} from './tab/tab-content.component'
import {TabContentAlternativeComponent} from './tab/tab-content-alternative.component'
...

@Component({
  selector: 'my-app',
  template: `
    <tab-container>
      <tab title="Tab 1" [contentRef]="normalContent"></tab>
      <tab title="Tab 2" [contentRef]="alternativeContent"></tab>
    </tab-container>
  `,
})
export class App {
  normalContent = TabContentComponent;
  alternativeContent = TabContentAlternativeComponent;
}

如果需要副本,它将由调用者创建,然后移动以构建成员。如果调用者通过临时(或其他右值),则不进行任何复制,只需一次移动。

对于没有高效移动构造函数的参数,接受对const的引用稍微有点效率,我会保留它。

如果函数不需要传递值的 copy ,则这些都不适用 - 如果不修改值并且不需要它,则继续使用const ref超出了函数执行的结束。就个人而言,我在构造函数中使用pass-by-value-and-move,但很少在我的其他函数中使用。

答案 1 :(得分:2)

真的,如果搬家建设非常便宜,你应该按价值计算。

在每种情况下,这都会导致理想情况下的一次额外移动。

但如果你真的必须避免这种情况,你可以这样做:

template<class T>
struct sink_of {
  void const* ptr = 0;
  T(*fn)(void const*) = 0;
  sink_of(T&& t):
    ptr( std::addressof(t) ),
    fn([](void const*ptr)->T{
      return std::move(*(T*)(ptr));
    })
  {}
  sink_of(T const& t):
    ptr( std::addressof(t) ),
    fn([](void const*ptr)->T{
      return *(T*)(ptr);
    })
  {}
  operator T() const&& {
    return fn(ptr);
  }
};

使用RVO / elision以一堆基于指针的开销和类型擦除为代价来避免额外的移动。

Here是一些演示

的测试代码
test( noisy nin ):n(std::move(nin)) {}
test( sink_of<noisy> nin ):n(std::move(nin)) {}

完全不同于noisy的1个move-construct。

&#34;完美&#34;版本

test( noisy const& nin ):n(nin) {}
test( noisy && nin ):n(std::move(nin)) {}

template<class Noisy, std::enable_if_t<std::is_same<noisy, std::decay_t<Noisy>>{}, int> = 0 >
test( Noisy && nin ):n(std::forward<Noisy>(nin)) {}

sink_of版本具有相同的复制/移动次数。

noisy是一种类型,用于打印有关其所涉及的移动/复制的信息,因此您可以看到通过省略来优化的内容)

当额外move对消除重要时,仅值得。对于vector,它不是。

另外,如果你有一个真正的临时&#34;你正在路过,那个按价值的一个和sink_of一样好,或者&#34;完美的&#34;的。