C++ 中常规 "for" 语句和基于范围的 "for" 语句有什么区别
What is the difference between regular "for" statement and range-based "for" statement in C++
那么,这两种说法有什么区别:
for(auto i : VectorName){}
for(auto i = VectorName.begin(); i != VectorName.end(); i++){}
比如我有这个程序:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main()
{
vector<char> vec = {'H','e','l','l','o','W','o','r','l','d','!'};
for(auto i = vec.begin(); i != vec.end(); i++) // This loop has error
{
cout << i << endl;
}
for(auto k : vec) //This loop has no problem
{
cout << k << endl;
}
return 0;
}
我很困惑,因为在这个例子中 Microsoft docs:
// cl /EHsc /nologo /W4
#include <deque>
using namespace std;
int main()
{
deque<double> dqDoubleData(10, 0.1);
for (auto iter = dqDoubleData.begin(); iter != dqDoubleData.end(); ++iter)
{ /* ... */ }
// prefer range-for loops with the following information in mind
// (this applies to any range-for with auto, not just deque)
for (auto elem : dqDoubleData) // COPIES elements, not much better than the previous examples
{ /* ... */ }
for (auto& elem : dqDoubleData) // observes and/or modifies elements IN-PLACE
{ /* ... */ }
for (const auto& elem : dqDoubleData) // observes elements IN-PLACE
{ /* ... */ }
}
他们注意到语句的范围并不比常规范围好。
在
for (auto i = vec.begin(); i != vec.end(); i++)
{
//cout << i << endl; // should be cout << *i << endl;
auto& k = *i;
cout << k << endl;
}
i
是一个迭代器,您必须推导它以检索几乎等于第二个代码段的值。
你的情况的不同之处在于,带有迭代器的第一个版本使用迭代器(这就是 cout << i << endl;
不起作用的原因),第二个版本(基于范围的 for 循环)给你副本、参考或常量参考。
所以这个:
for(auto i = vec.begin(); i != vec.end(); i++)
{
cout << i << endl; // should be *i
}
使用迭代器(vec.begin()
为您提供第一个元素的迭代器)。
而这个:
for(auto i : vec)
{
cout << i << endl;
}
使用向量中元素的副本。
同时:
for(auto& i : vec)
{
cout << i << endl;
}
使用对矢量元素的引用。
常规 for 循环使用显式循环变量,在您的示例中是迭代器 i
或 iter
(很多时候它只是一个整数)。例如,要访问向量中的元素,您需要使用循环变量从向量中提取元素。
Range-based for loops 自动给你你循环的容器内的元素,所以不需要提取循环内的元素,你可以立即使用 k
/elem
.
关于您提到的评论:没有引用的特定基于范围的样式通常不利于性能(如果不需要复制)。
So, what is the difference between these two statement:
for(auto i : VectorName){}
for(auto i = VectorName.begin(); i != VectorName.end(); i++){}
第一个将遍历集合中的每个项; i
是项目的副本。
第二个给你更多控制范围; i
是一个迭代器,解引用访问项。
那么,这两种说法有什么区别:
for(auto i : VectorName){}
for(auto i = VectorName.begin(); i != VectorName.end(); i++){}
比如我有这个程序:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main()
{
vector<char> vec = {'H','e','l','l','o','W','o','r','l','d','!'};
for(auto i = vec.begin(); i != vec.end(); i++) // This loop has error
{
cout << i << endl;
}
for(auto k : vec) //This loop has no problem
{
cout << k << endl;
}
return 0;
}
我很困惑,因为在这个例子中 Microsoft docs:
// cl /EHsc /nologo /W4
#include <deque>
using namespace std;
int main()
{
deque<double> dqDoubleData(10, 0.1);
for (auto iter = dqDoubleData.begin(); iter != dqDoubleData.end(); ++iter)
{ /* ... */ }
// prefer range-for loops with the following information in mind
// (this applies to any range-for with auto, not just deque)
for (auto elem : dqDoubleData) // COPIES elements, not much better than the previous examples
{ /* ... */ }
for (auto& elem : dqDoubleData) // observes and/or modifies elements IN-PLACE
{ /* ... */ }
for (const auto& elem : dqDoubleData) // observes elements IN-PLACE
{ /* ... */ }
}
他们注意到语句的范围并不比常规范围好。
在
for (auto i = vec.begin(); i != vec.end(); i++)
{
//cout << i << endl; // should be cout << *i << endl;
auto& k = *i;
cout << k << endl;
}
i
是一个迭代器,您必须推导它以检索几乎等于第二个代码段的值。
你的情况的不同之处在于,带有迭代器的第一个版本使用迭代器(这就是 cout << i << endl;
不起作用的原因),第二个版本(基于范围的 for 循环)给你副本、参考或常量参考。
所以这个:
for(auto i = vec.begin(); i != vec.end(); i++)
{
cout << i << endl; // should be *i
}
使用迭代器(vec.begin()
为您提供第一个元素的迭代器)。
而这个:
for(auto i : vec)
{
cout << i << endl;
}
使用向量中元素的副本。
同时:
for(auto& i : vec)
{
cout << i << endl;
}
使用对矢量元素的引用。
常规 for 循环使用显式循环变量,在您的示例中是迭代器 i
或 iter
(很多时候它只是一个整数)。例如,要访问向量中的元素,您需要使用循环变量从向量中提取元素。
Range-based for loops 自动给你你循环的容器内的元素,所以不需要提取循环内的元素,你可以立即使用 k
/elem
.
关于您提到的评论:没有引用的特定基于范围的样式通常不利于性能(如果不需要复制)。
So, what is the difference between these two statement:
for(auto i : VectorName){} for(auto i = VectorName.begin(); i != VectorName.end(); i++){}
第一个将遍历集合中的每个项; i
是项目的副本。
第二个给你更多控制范围; i
是一个迭代器,解引用访问项。