【问题标题】:c++ for loops(c++11 way and older versions way)c++ for 循环(c++11 方式和旧版本方式)
【发布时间】:2014-01-27 10:11:44
【问题描述】:

我刚开始学习c++。 我被教导如何编写一个简单的 for 循环

例如

for (int i = 0; i < vector.size(); i++) {
    //do stuff
}

但现在经常看到人们在他们的for循环中使用auto这个词。

假设我有一个包含一些数据的向量,这些数据将被带到地图上

例如

c++11 方式

vector<char> vec;
map<char, int> myMap;
vec.push_back('a');
vec.push_back('b');
vec.push_back('b');
vec.push_back('c');

// Loop through the vector
for (auto x : vec) {
   ++myMap[x]; 
}

for (auto x : myMap) {

}

这是否等同于

vector<char> vec;
map<char, int> myMap;
vec.push_back('a');
vec.push_back('b');
vec.push_back('b');
vec.push_back('c');

for (int x = 0; x < v.size(); x++) {
    ++myMap[v[x]];
}

for (int x = 0; x < myMap.size() x++) {
   //print content in map
}

【问题讨论】:

  • 这两个代码片段都不会编译 - 至少这是它们的共同点。
  • 我也不相信可以取消引用指向字符类型的自动类型。如果我错了,请纠正我。
  • 在第一个中,您尝试使用 string 索引到 map&lt;char, int&gt; (已被取消引用,不少,但让我们忽略那部分)。在第二个你试图取消引用char。
  • 我向所有人道歉。我尽力想出一个例子。如果我给出的示例具有误导性,请原谅我。

标签: c++ c++11


【解决方案1】:

它在效果上是等效的,而不是在效率方面。这是标准定义的确切翻译:

for (auto element : container) {
  //Stuff
}

被翻译成这个基于迭代器的循环:

auto&& __range = container; 
for (auto __itr = std::begin(container),  __end = std::end(container);
     __itr != __end; ++__itr) { 
   element = *__itr;
   //Stuff
}

特别是,它的不同之处在于它只评估结束一次(而不是多次调用v.size())并且它使用迭代器而不是索引。它还提供了一个更简洁的界面:

  1. 您知道它必须遍历所有元素(除非您使用中断/继续)。
  2. 您知道它必须一次循环一个元素(除非您使用中断/继续)。
  3. 它通过语法糖隐藏了索引/迭代器的使用:)。

其他几件事:

1) auto 是一个单独的语言功能。您不需要使用auto 来使用基于范围的 for 循环,例如:

for (int i : { 1, 2, 3, 4, 5}) {
   cout << i << endl;
}

打印数字 1-5 是一种完全合法的方式。

2) 与其使用 push_back 填充示例向量,不如使用“通用初始化”:

vector<char> vec { 'a', 'b', 'c', 'd' };

3) 当对非原始类型使用基于范围的 for 循环时,最好使用 auto&amp; 或 const auto&amp; 作为范围声明类型。例如

vector<string> v { "Hello", "world" };
for (const auto& elt : v) {
  cout << elt << endl;
}

我们这样做是因为复制原语以外的东西通常很昂贵,并且默认情况下会进行复制。这里我们取了一个别名,为我们节省了一个字符串副本,从而节省了分配的性能成本。

Source

技术性:我给出的翻译有点不准确,因为它没有以与标准相同的方式处理所有情况(它更喜欢成员函数开始/结束并且数组得到特殊处理)。为了便于理解,我对其进行了简化。有关更多详细信息,请参阅上面的来源。

【讨论】:

    【解决方案2】:

    您不能取消引用 int 变量。您的旧样式示例需要稍微更新:

    for (int x= 0 ; ( x < v.size() ) ; x ++ ) {
      ++ myMap[ v[x] ] ;
    }
    

    但是在老式 C++ 中没有人真正做到这一点,他们使用迭代器:

    for ( vector<int>::iterator itptr= v.begin() ; ( itptr != v.end() ) ; ++ itptr ) {
      ++ myMap[ * itptr ] ;
    }
    

    由于auto,这种形式的 for 循环在 C++11 中变得更容易:

    for ( auto itptr= v.begin() ; ( itptr != v.end() ) ; ++ itptr ) {
      ++ myMap[ * itptr ] ;
    }
    

    但正如你所见,新的for 形式是最简单的:

    // Loop through the vector
    for (auto x : vec) {
     ++myMap[x]; 
    }
    

    但请注意,我没有取消引用 x,x 是角色。

    【讨论】:

    • +1 用于提及新的自动类型,并表示不要取消引用 x,因为它指向一个字符。
    【解决方案3】:

    是的,它们是等价的。

    除了这两种情况,您应该不尝试尊重x,因为在这两种情况下,这都是语法错误。

    【讨论】:

    • @user3175729:我已经更新了我的答案以适应您对问题的修改。
    • 不,它们不相等。这个循环 for(int i = 0; i::size_type i = 0; i
    • 我不这么认为,因为我已经多次遇到程序中止的原因是在此类循环中使用 int。现在很多平台都是 64 位的。
    • @Vlad: 不,int 这里不会中止任何事情;您之前的评论可能会中止您的 SO 声誉(例如)。
    • @Vlad:好的,我会在我阅读足够多的时候告诉你。谢谢你的建议。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-11
    • 1970-01-01
    相关资源
    最近更新 更多