首页 文章

C 11基于范围的循环:按值获取项目或引用const

提问于
浏览
171

阅读一些基于范围的循环的例子,他们提出了两种主要方式1,2,3,4

std::vector<MyClass> vec;

for (auto &x : vec)
{
  // x is a reference to an item of vec
  // We can change vec's items by changing x 
}

要么

for (auto x : vec)
{
  // Value of x is copied from an item of vec
  // We can not change vec's items by changing x
}

好 .

当我们不需要更改 vec 项目时,IMO,示例建议使用第二个版本(按值) . 为什么他们没有提出 const 引用的内容(至少我没有找到任何直接的建议):

for (auto const &x : vec) // <-- see const keyword
{
  // x is a reference to an const item of vec
  // We can not change vec's items by changing x 
}

Isn 't it better? Doesn' t它避免了每次迭代中的冗余副本,而它是 const

4 回答

  • 21

    如果您不想更改项目以及想要避免复制,那么 auto const & 是正确的选择:

    for (auto const &x : vec)
    

    谁建议你使用 auto & 是错误的 . 别理他们 .

    这是概述:

    • 如果要处理副本,请选择 auto x .

    • 如果要使用原始项目,请选择 auto &x ,并可以对其进行修改 .

    • 如果要使用原始项目,请选择 auto const &x ,不会修改它们 .

  • 3

    如果您有 std::vector<int>std::vector<double> ,那么使用 auto (带值复制)而不是 const auto& 就可以了,因为复制 intdouble 很便宜:

    for (auto x : vec)
        ....
    

    但是如果你有一个 std::vector<MyClass> ,其中 MyClass 有一些非平凡的复制语义(例如 std::string ,一些复杂的自定义类等),那么我建议使用 const auto& to avoid deep-copies

    for (const auto & x : vec)
        ....
    
  • 314

    当我们不需要更改vec项时,示例建议使用第一个版本 .

    然后他们给出了错误的建议 .

    为什么他们不建议const引用的东西

    因为他们给出了错误的建议:-)你提到的是正确的 . 如果您只想要 observe 一个对象,则无需创建副本,也无需对其进行非 const 引用 .

    EDIT:

    我看到你链接的引用都提供迭代一系列 int 值或其他一些基本数据类型的例子 . 在这种情况下,由于复制 int 并不昂贵,因此创建副本基本上等同于(如果不是更有效)观察 const & .

    但是,对于用户定义的类型,通常不是这种情况 . 复制UDT可能很昂贵,如果您没有理由创建副本(例如修改检索到的对象而不更改原始副本),则最好使用 const & .

  • 1

    我将在这里反对并说在基于循环的范围内不需要 auto const & . 如果您认为以下函数是愚蠢的(不是出于其目的,而是出现在它的编写方式),请告诉我:

    long long SafePop(std::vector<uint32_t>& v)
    {
        auto const& cv = v;
        long long n = -1;
        if (!cv.empty())
        {
            n = cv.back();
            v.pop_back();
        }
        return n;
    }
    

    这里,作者创建了一个对 v 的const引用,用于所有不修改v的操作 . 在我看来,这是愚蠢的,并且可以使用 auto const & 作为基于for循环的范围中的变量进行相同的参数只是 auto & .

相关问题