145

const auto&如果我想执行只读操作就足够了。然而,我遇到了

for (auto&& e : v)  // v is non-const

最近几次。这让我想知道:

auto&与or相比,在某些不明显的极端情况下,使用转发引用是否有一些性能优势const auto&

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


更新 我在收藏夹中找到的两个示例:

迭代基本类型时使用 const 引用有什么缺点吗?
我可以使用基于范围的 for 循环轻松迭代地图的值吗?

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

4

3 回答 3

115

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

#include <vector>

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

这不会编译,因为vector<bool>::reference从返回的右值iterator不会绑定到非常量左值引用。但这会起作用:

#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&&将成为首选解决方案。

于 2012-10-29T22:50:12.777 回答
28

使用基于范围的循环auto&&通用引用for具有捕获所获得内容的优势。对于大多数类型的迭代器,您可能会得到 aT&或 a T const&for some type 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));
}

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

于 2012-10-30T19:35:53.543 回答
8

我几乎总是使用auto&&. 为什么在不必要的情况下被边缘案例咬伤?打字也更短,我只是觉得它更……透明。当您使用 时auto&& x,您就知道每次x都准确无误。*it

于 2012-10-30T19:40:39.170 回答