在迭代向量时,自动类型与具体类型有何区别?

7
我正在阅读的书提供了一个示例,用于迭代遍历 vector
for (auto &e: v) {
  cout << e << endl;
}

假设v被声明为vector<int> v,换句话说,我们知道这个集合中的元素类型是int
在任何情况下使用auto是否更好或更受欢迎?
for (int &e: v) {
  cout << e << endl;
}

为什么?
2个回答

6
是的。首选使用auto。因为如果您将v的声明从以下更改:
std::vector<int> v;  //before 

转换为:

std::vector<float> v; //after

如果你在for循环中使用int &,那么你也需要改变它。但是使用auto就不需要改变了!
在我看来,使用auto有点像面向接口编程。因此,如果你在循环中执行+=操作,并且只要循环变量e的类型支持+=操作,你就不需要关心它的类型,auto就是解决方案:
for(auto & e : v)
{
      e += 2;
}

在这个例子中,你只需要关心 e 的类型支持右侧为 int+=。即使是用户自定义的类型,只要定义了 operator+=(int) 或者 operator+=(T)(其中 T 是一种支持从 int 隐式转换的类型),也可以正常工作。就像你在编程时使用接口一样。
std::vector<Animal*> animals;
animals.push_back(new Dog());
animals.push_back(new Cat());
animals.push_back(new Horse());

for(size_t i = 0 ; i < animals.size(); ++i)
{
       animals[i]->eat(food); //program to interface
}

当然,您希望将此循环写成以下形式:

for(Animal * animal : animals)
{
       animal->eat(food); //still program to interface
}

或者仅仅是这样:
for(auto animal : animals)
{
       animal->eat(food); //still program to interface
}

仍然是面向接口编程

但与此同时,@David评论中的观点值得注意。


6
这句话可以有两种理解方式,也许最好的方式是让编译器报告一个编译错误,指出int&不能从float&中设置而不是默默地接受本应与整数一起工作的代码...并不是说int&是更好的选择,这完全取决于你在for循环主体中做什么,如果不依赖于确切类型,则使用auto会更好。 - David Rodríguez - dribeas
1
同意。在大多数情况下,auto&就可以了...但是我还不太习惯类型不明确的情况 :)(除非我真的不想知道!) - David Rodríguez - dribeas
@Nawaz:除了你所说的语法错误之外;(答案的后半部分中的容器保存的是Animal*,但你却像它是Animal一样访问它) - David Rodríguez - dribeas
@DavidRodríguez-dribeas:哎呀,已经修复了。(我目前在办公室使用 C# 工作,这也影响了我在这里使用的 C++ 语法)。 - Nawaz
还要注意,如果您将向量更改为列表或集合,则带有c + 0x语法的代码将起作用,除非容器具有begin()和end()。 - galadog
显示剩余6条评论

1

在您的第一个示例中,您对向量元素的依赖较少。

假设在一个月内,您需要将更大的整数存储到您的向量中,因此您将不得不使用std::vector<int64_t>或其他更宽的类型。现在,遍历该向量的所有代码都是无效的。您必须修改每个代码:

for (int &e: v) {}

针对:

for (int64_t &e: v) {}

这就是为什么最好让auto推断内部类型。这样,您可以修改存储在向量中的类型为另一个兼容的类型,并且所有代码仍将正常工作。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接