Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-mvc/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++11 提供移动参数的构造函数的惯用方法_C++11_Move Semantics_Rvalue Reference - Fatal编程技术网

C++11 提供移动参数的构造函数的惯用方法

C++11 提供移动参数的构造函数的惯用方法,c++11,move-semantics,rvalue-reference,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; }; #包括 福班 { 公众: Foo(const std::vector&a,c

假设我有以下课程:

#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;
};
#包括
福班
{
公众:
Foo(const std::vector&a,const std::vector&b)
:a{a},b{b}{
私人:
std::载体a,b;
};
但是现在我想解释一下,在这种情况下,构造函数的调用者可能会将临时变量传递给它,我想将这些临时变量适当地移动到
a
b

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

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

这个问题也适用于所有函数

这样做的惯用方式是什么?还是我完全忽略了一些重要的内容?

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

Foo(std::vector<int> a, std::vector<int> b)
    : a{ std::move(a) },
      b{ std::move(b) }
{}
Foo(标准::向量a,标准::向量b)
:a{std::move(a)},
b{std::move(b)}
{}
如果需要副本,则调用者将创建副本,然后将其从移动到构造成员。如果调用方传递了一个临时值(或其他右值),则不会进行复制,只进行一次移动

对于没有有效移动构造函数的参数,那么接受对const的引用稍微有效一些,我会保留这一点

如果函数不需要传递值的副本,则所有这些都不适用-如果不修改该值并且不需要它在函数执行结束后继续使用const ref。就我个人而言,我在构造函数中使用按值传递并自由移动,但在其他函数中很少使用。

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

Foo(std::vector<int> a, std::vector<int> b)
    : a{ std::move(a) },
      b{ std::move(b) }
{}
Foo(标准::向量a,标准::向量b)
:a{std::move(a)},
b{std::move(b)}
{}
如果需要副本,则调用者将创建副本,然后将其从移动到构造成员。如果调用方传递了一个临时值(或其他右值),则不会进行复制,只进行一次移动

对于没有有效移动构造函数的参数,那么接受对const的引用稍微有效一些,我会保留这一点


如果函数不需要传递值的副本,则所有这些都不适用-如果不修改该值并且不需要它在函数执行结束后继续使用const ref。就个人而言,我在构造函数中大量使用传递值和移动,但在其他函数中很少使用。

实际上,如果移动构造非常便宜,您应该按值移动

这会导致在每种情况下都比理想情况多移动一次

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

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);
  }
};

模板
测试(嘈杂和nin):n(标准::前向(nin)){}
与版本的接收器具有相同的复制/移动次数

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

只有当额外的
移动
非常重要时,才值得这样做。对于
向量
,它不是


此外,如果你有一个“真正的临时”你通过,按价值的一个是一样好的水槽或“完美”的。真的,你应该采取的价值,如果移动建设是非常便宜的

这会导致在每种情况下都比理想情况多移动一次

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

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);
  }
};

模板
测试(嘈杂和nin):n(标准::前向(nin)){}
与版本的接收器具有相同的复制/移动次数

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

只有当额外的
移动
非常重要时,才值得这样做。对于
向量
,它不是


此外,如果您要传递一个“真正的临时”参数,则按值传递的参数与按值传递的参数或“完美”参数一样好。

我看到的一个解决方案是按值获取这两个参数,然后移动它们。虽然我看到了这一争议,但我再也找不到来源了:/哦,是的,你是对的。我将编辑我的答案:p。我看到的一个解决方案是按值获取两个参数,然后移动它们。虽然我看到了这一争议,但我再也找不到来源了:/哦,是的,你是对的。我将编辑我的答案:p.临时变量确实会被移动,但用左值调用这个ctor会稍微慢一点,因为它是被复制和移动的,而不是被复制的?稍微慢一点,但想法是移动构造预计会非常便宜。对于
std::vector
,您将很难测量差异。而且与编写2^n个不同的构造函数相比,它的难度要小得多,也不容易出错!这种方法对于
vector
来说是一个不错的选择,因为移动与复制相比非常便宜。只是要小心将这种方法推广到其他可能没有这种特性的类型。@Jupiter:没有一种正确的方法可以做到这一点。对于每种情况,我都会计算拷贝数和移动数,并估计每种拷贝数和移动数的成本。有3种方法,每种方法都有优点和缺点。这一个,2^n解决方案(对于单参数来说非常好)和约束模板解决方案(性能完美,但读写不好,容易出错,而且常常是杀伤力过大)。对于
vector
,我建议采用按价值计算的方法。翻新旧房子通常比从头开始建造新房子更困难、更昂贵。这需要不同的技能组合,结果也不一样。但有时翻新是唯一可行的答案,尤其是如果你
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)) {}