【问题标题】:Range for loop through forwarded iterable循环通过转发可迭代的范围
【发布时间】:2015-05-25 13:59:31
【问题描述】:

假设我有以下情况

template<typename T>
void func(T&& arg)
{
    for (auto elem : arg) // ***
    {
        // do stuff
    }
}

其中 arg 是 iterabe(向量或初始化列表等)。我对 *** 行感兴趣:以下哪个更好:

auto elem
auto& elem
`const` of the above

我想选项 (3) 包含在参数推导中(如果需要,auto 会在其中放置一个 const)。 func 也被称为这样的事实

func(std::forward<T>(arg)); 

改变什么?

【问题讨论】:

    标签: c++ c++11 argument-passing c++14


    【解决方案1】:

    这完全取决于容器中的内容。

    如果容器的值是大而重的对象,使用引用会更好,因为它可以避免复制它。

    另一方面,如果容器的值只是小值,尤其是原生数据类型,显式副本将鼓励更好的编译器优化,因为编译器可以假设,在迭代期间,当前使用的值不能通过以下方式修改另一个引用或指针。

    【讨论】:

      【解决方案2】:

      这完全取决于你想做什么以及 T 的类型是什么。

      你应该使用:

      for (auto elem : arg)
      {
            // do stuff
      }
      

      当 T 是原始类型(复制成本低)并且您不想修改“arg”集合时。

      你应该使用:

      for (auto& elem : arg)
      {
            // do stuff
      }
      

      如果你想修改 'arg' 集合。

      你应该使用:

      for (const auto& elem : arg)
      {
            // do stuff
      }
      

      当 T 不是原始类型(复制成本高),并且您承诺不会更改 'arg' 集合时。

      【讨论】:

        【解决方案3】:

        在基于范围的for 循环中使用auto 声明变量几乎是总是错误的。只有保证范围使用未变异的内置对象时,它才是正确的。我通常不会在这里使用auto(公平地说,我也不会首先使用基于范围的for,而是更喜欢算法)。

        使用auto&amp;*it 的结果限制为迭代器it 的范围为T&amp;T const&amp; 用于某些合适的类型T。例如,它不允许迭代 std::vector&lt;bool&gt;。如果允许元素发生变异,这是一个合理的选择。使用auto const&amp;*it 的结果限制为左值或具有复制构造函数,并将防止范围发生变异。根据用途,这可能是一个合理的选择。

        一般情况下,默认选择应为auto&amp;&amp;,因为它对*it 的结果没有任何限制,除了不是void

        所以,总结一下:

        • for (auto elem: arg) 如果元素必须是内置的并且没有变异。
        • for (auto&amp; elem: arg) 如果元素是左值并且允许变异。
        • for (auto const&amp; elem: arg) 如果元素是左值但没有变异。
        • for (auto&amp;&amp; elem: arg) 在所有无关紧要的情况下。我认为始终使用auto&amp;&amp; 是可以的。

        【讨论】:

        • 如果你想让本地副本发生变异,auto 也是正确的。一个不寻常的要求,但可以存在。或者,如果您想要容器元素上的其他操作不会发生变异的本地副本,const auto(请注意使迭代器无效的危险:elememt 修改证明,而不是容器本身的修改证明)。这些都有些罕见,第二个更是如此。
        • 对最后一个建议不太确定(始终使用auto&amp;&amp;)。我觉得有时不使用auto const&amp; 会掩盖错误。考虑以下情况,假设作者忘记了一个=std::vector&lt;std::map&lt;int, int&gt;&gt; v; for (auto&amp;&amp; m : v) { if (m[1] = 2) { } }。对于auto&amp;&amp;,这将产生一个运行时错误,而auto const&amp; 使它成为一个编译器错误。
        猜你喜欢
        • 1970-01-01
        • 2013-01-14
        • 2023-02-23
        • 1970-01-01
        • 2013-03-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-04-20
        相关资源
        最近更新 更多