【问题标题】:C++11 pass vector to constructorC ++ 11将向量传递给构造函数
【发布时间】:2016-04-20 08:23:49
【问题描述】:

我整天都在阅读有关传递参数的最佳有效方式的信息,但我很困惑。我想传递这样的向量:

Foo f({1,2,3});

我只是想用传递的向量初始化我的 _member 变量。现在的问题是我的构造函数应该怎么看:

// pass by value
Foo (vector<int> vec) : _member{vec} {}

// const reference
Foo (const vector<int>& vec) : _member{vec} {}

// rvalue reference
Foo (vector<int>&& vec) : _member{std::move(vec)} {}

【问题讨论】:

  • 你的传递值也应该有一个std::move
  • 将新向量初始化为vector并传递
  • 请不要破坏您的帖子。如果您不希望帖子与您再关联,read this

标签: c++ c++11 vector constructor


【解决方案1】:

最简单的方法是按值取向量,然后移动它:

Foo (vector<int> vec) : _member{std::move(vec)} {}

与一对const vector&lt;int&gt;&amp;/vector&lt;int&gt;&amp;&amp; 重载相比,您最多需要支付一个额外的移动(这对于向量来说非常便宜),但不必编写两个构造函数(如果您有多个参数)。

【讨论】:

  • “额外”移动是什么意思?与什么相比?
  • @Petrof 这同样适用于小型和大型向量。
  • @Petrof 按值与按右值引用对临时对象同样有效(由于省略)。如果您想让使用左值向量构造 Foo 成为错误,请使用右值引用。
【解决方案2】:

如今,在许多圈子中,通过价值传递是一种时尚。由于各种原因,我认为对于构造函数来说这是一个不错的选择,所以我同意 T.C. 的回答。然而,关于传递参数(到非构造函数)的最佳方式的更广泛的问题,我很少推荐按值传递。我真的非常强烈建议您听听 Herb Sutter 关于该主题的这部分演讲:https://youtu.be/xnqTKD8uD64?t=51m34s

总而言之,在构造函数之外:与简单的 const-ref 传递相比,按值传递提供更差的最坏情况性能保证,它在所有情况下都比 const-ref/rvalue-ref 重载提供更差的性能,它更难为了提供异常保证,它对多态类型进行切片,当复制是有条件的时,它不能使用。

在大多数情况下,您要么在合理范围内不关心性能,要么非常关心。在第一种情况下,使用 const-ref 更简单、更容易。在第二种情况下,按值传递还不够好。同样,请记住,构造函数的不同有几个不同的原因(它们是移动构造事物而不是移动分配,它们采用许多参数,这会强烈影响您需要的重载数量)。

不幸的是,这个问题没有这么简单的单一答案。最终这两种方法都足够好,但我认为要掌握 C++,你想知道两者的优缺点。

【讨论】:

  • "与简单的通过 const-ref 传递相比,按值传递提供更差的最坏情况性能保证" 除非您无论如何都需要副本;萨特说了同样的话。 “在所有情况下,它的性能都比 const-ref/rvalue-ref 重载更差” 在许多情况下,这只是一次移动的成本,但它总是花费两倍的代码。 “提供异常保证变得更加困难” 实际上,它使它们变得更容易,因为负担转移到了调用者身上。 “它分割多态类型” 完全正交的问题。 “复制有条件时不能使用”见第一点。
  • 条件性和多态性只是额外的特殊情况,需要牢记在心,因此它们使事情变得更加复杂。通常,性能并不重要,当性能不重要时, const ref 应该是您的默认设置。至于性能,那不是 Sutter 所说的。 Sutter 将复制构造(按值传递)与复制分配(按常量引用)进行比较;并指出,在许多常见类型(向量/字符串)的实际用例中,复制分配显着便宜。换句话说:如果我们忽略 perf,按值传递显然会更糟,而且对于 perf 也不是很好。
  • @ildjarn 实际上,您对异常保证的看法不正确。如果你有一个函数void f(std::vector&lt;double&gt; x, std::unique_ptr&lt;int&gt; y),你就有一个函数,通过它的签名永远不能以有意义的方式提供 noexcept 或强保证。是的,“技术上”异常不是由函数体抛出的,因此可以将其标记为 noexcept,但这是非常荒谬的(正如 Sutter 也提到的)。如果您编写了相同的函数以通过 const ref 和 rvalue ref 获取,则可以根据主体的编写方式有意义地提供所需的任何保证。
【解决方案3】:

在这种特殊情况下,您传递的是rvalue,所以第三个选择是最好的。

【讨论】:

  • 因为一个调用者代表每个调用者?
  • 当然不是,但既然他提供了一个具体的例子,我相信最好也有一个具体例子的最佳选择。
猜你喜欢
  • 2019-08-07
  • 1970-01-01
  • 2021-05-15
  • 2012-01-12
  • 2011-12-02
  • 2018-05-09
  • 2015-10-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多