在基于范围的for循环中使用转发引用有什么好处?

时间:2012-10-29 22:40:43

标签: c++ performance for-loop c++11 move-semantics

如果我想执行只读操作,

const auto&就足够了。但是,我已经碰到了

for (auto&& e : v)  // v is non-const
最近几次。这让我想知道:

auto&const auto&相比,在某些模糊的角落案例中,使用转发引用是否有一些性能优势?

shared_ptr是晦涩的角落案件的嫌疑人)


更新 我在我的最爱中找到的两个例子:

Any disadvantage of using const reference when iterating over basic types?
Can I easily iterate over the values of a map using a range-based for loop?

请专注于这个问题:为什么我要使用auto&&在基于范围的for循环中?

3 个答案:

答案 0 :(得分:82)

我能看到的唯一优势是当序列迭代器返回代理引用时,你需要以非const方式对该引用进行操作。例如,考虑:

#include <vector>

int main()
{
    std::vector<bool> v(10);
    for (auto& e : v)
        e = true;
}

这不会编译,因为从vector<bool>::reference返回的rvalue iterator不会绑定到非const左值引用。但这会奏效:

#include <vector>

int main()
{
    std::vector<bool> v(10);
    for (auto&& e : v)
        e = true;
}

所有这一切,除非你知道你需要满足这样一个用例,否则我不会以这种方式编码。即我不会无偿地这样做,因为确实让人们想知道你在做什么。如果我这样做了,那么为什么包括评论并不会有害:

#include <vector>

int main()
{
    std::vector<bool> v(10);
    // using auto&& so that I can handle the rvalue reference
    //   returned for the vector<bool> case
    for (auto&& e : v)
        e = true;
}

修改

我的最后一个案例应该是一个有意义的模板。如果您知道循环始终处理代理引用,则auto将与auto&&一样有效。但是当循环有时处理非代理引用和有时代理引用时,我认为auto&&将成为首选的解决方案。

答案 1 :(得分:25)

auto&&universal references与基于范围的for循环一起使用,可以捕获您获得的内容。对于大多数类型的迭代器,对于某些类型T&,您可能会获得T const&T。有趣的情况是,取消引用迭代器会产生一个临时的:C ++ 2011得到了宽松的要求,并且迭代器不一定需要产生左值。通用引用的使用与std::for_each()

中的参数转发相匹配
template <typename InIt, typename F>
F std::for_each(InIt it, InIt end, F f) {
    for (; it != end; ++it) {
        f(*it); // <---------------------- here
    }
    return f;
}

函数对象f可以不同方式处理T&T const&T。为什么基于范围的for - 循环的主体应该不同?当然,要实际利用通用引用推断出类型,你需要相应地传递它们:

for (auto&& x: range) {
    f(std::forward<decltype(x)>(x));
}

当然,使用std::forward()表示您接受要移动的任何返回值。这样的对象在非模板代码中是否有用,我不知道(还是?)。我可以想象使用通用引用可以为编译器提供更多信息来做正确的事情。在模板化代码中,它不会对对象应该发生什么做出任何决定。

答案 2 :(得分:7)

我几乎总是使用auto&&。当你不需要时,为什么会被边缘情况所困扰?键入也更短,我发现它更透明。当您使用auto&& x时,您每次都知道x正是*it