【问题标题】:move constructor when multiple arguments多个参数时移动构造函数
【发布时间】:2015-11-19 20:15:11
【问题描述】:

我有第一个类似这样的构造函数

X::X(const std::vector<int>& v1, const std::vector<int>& v2, const std::vector<int>& v3) : _v1(v1), _v2(v2), _v3(v3){
} // _v1 , _v2 and _v3 are members

对于这种行为,我还应该实现移动构造函数版本

X::X(std::vector<int>&&, std::vector<int>&&, std::vector<int>&&);

但也可以像这样混合使用 const 左值引用和右值引用的参数类型

X::X(const std::vector<int>&, std::vector<int>&&, const std::vector<int>&);

是实现所有可能的构造函数的最佳实践,即 2^3 吗?

【问题讨论】:

  • 任何不以X&amp;&amp; 作为唯一参数的构造函数都不是移动构造函数,它只是另一个常规构造函数。一般如果要优化这种类型的构造函数,应该使用模板和完美转发。
  • 你的第二个例子不是move constructor,虽然我明白你的意思。一种可能是使用“通用引用”和 sfinae 来约束类型(类似于these lines),但我觉得这有点混淆。

标签: c++ constructor arguments


【解决方案1】:

由于它是我们在这里讨论的构造函数,因此仅按值获取参数并移动它们是相当有效的:

X::X(std::vector<int> v1, std::vector<int> v2, std::vector<int> v3)
    : _v1(std::move(v1)), _v2(std::move(v2)), _v3(std::move(v3)) {}

根据实际参数,每个向量最多需要额外移动一次。但是移动很便宜,而且你不必编写 8 个单独的构造函数或一些难以理解的 SFINAE 混乱。

请注意,如果您要进行作业,则考虑因素会完全不同。复制构造+移动分配可能比简单的复制分配效率低得多,因为后者可能能够重用分配给对象所拥有的资源。当您构建一个新对象时,这个因素不会发挥作用,因为没有可重用的资源。

【讨论】:

    【解决方案2】:

    或者通过值传递向量,您可以使用转发参考

    template <typename T1, typename T2, typename T3>
    X::X(T1&& v1, T2&& v2, T3&& v3) :
        _v1(std::forward<T1>(v1)),
        _v2(std::forward<T2>(v2)),
        _v3(std::forward<T3>(v3))
    {}
    

    编辑

    正如评论中所说,缺点是它接受了太多的参数类型。在大多数情况下,向量构造函数会出错,但例如一个向量构造函数采用int,因此X(42, std::vector&lt;int&gt;{42}, v3) 可以工作(v1 是一个具有 42 个元素的向量 0v2 一个向量1 个元素 42) 可能是意外的。

    SFINAE 可以添加限制,但语法很冗长。

    【讨论】:

    • 只是为了补充这个答案,TC 的评论是您可能想要使用 sfinae 的原因,但正如 TC 前面所说的(正如您在 this example 中看到的那样),它使代码丑陋。
    猜你喜欢
    • 2018-05-08
    • 2016-09-02
    • 2016-06-20
    • 2013-03-16
    • 2011-05-22
    • 1970-01-01
    • 1970-01-01
    • 2018-02-02
    • 2013-02-05
    相关资源
    最近更新 更多