我是否应该使用新的C ++ 11“自动”功能,尤其是在循环中?


20

使用auto关键字的利弊是什么,尤其是在for循环中?

for(std::vector<T>::iterator it = x.begin(); it != x.end(); it++ )
{
   it->something();
}

for(std::map<T>::iterator it = x.begin(); it != x.end(); it++ )
{
   it->second->something();
}

for(auto it = x.begin(); it != x.end(); it++ )
{
   it->??
}

似乎,如果您不知道是否有地图或矢量的迭代器,就不会使用first还是second直接访问对象的属性,是吗?

这让我想起了C#关于是否使用关键字的争论var。到目前为止,我得到的印象是,在C ++世界中,人们autovar在C#世界中更愿意采用关键词。对我来说,我的第一个直觉是我想知道变量的类型,以便知道可以对它执行哪些操作。


3
等待!有人在争论是否要使用var?我错过了。
pdr 2012年

21
更妙的是,你可以使用for (auto& it : x)(或不提,如果你想复制)
陶Szelei

7
在我看来,如果您正在编写循环以遍历的内容,x而您甚至都不知道是什么x,就不应该首先编写该循环;-)
nikie 2012年

@fish:基于范围的for循环规则,但是我会很学问并做了:'for(T&it:x)'而不是在使用基于范围的for循环时,因为我觉得使用auto的信息较少。我心里有点滥用汽车。
martiert

使用var的斗争有些愚蠢,尤其是回想起来。请参阅货物崇拜编程
Craig

Answers:


38

C ++的动机更加极端,因为由于元编程和其他原因,类型可能比C#类型更加复杂和复杂。auto与显式类型相比,其读写速度更快,并且更具灵活性/可维护性。我的意思是,您想开始输入吗

boost::multi_map<NodeType, indexed_by<ordered_unique<identity<NodeType>>, hashed_non_unique<identity<NodeType>, custom_hasher>>::iterator_type<0> it

那甚至不是完整的类型。我错过了几个模板参数。


8
该示例为+1,但这也说明了“现代” C ++的状态。
zvrba 2012年

22
@zvrba:是的,通用工具比C#的功能强大得多。
DeadMG

4
这就是typedef的目的
gbjbaanb

19
@gbjbaanb不,这就是auto目的。通过设计。typedef有帮助,但有auto更多帮助。
康拉德·鲁道夫

1
typedef使“不使用auto生成很长的类型”这一论点无效
Michael

28

在您的示例中:

for(auto it = x.begin(); it != x.end(); i++)
{
  it->??
}

必须有一个x可见的声明。因此,的类型it应该很明显。如果类型x不明显,则说明方法太长或类太大。


7
另外,x对于容器来说,这是一个非常糟糕的变量名。在某些情况下,您很可能只看一下(在语义上有价值)的名称并推断出可能的操作。
Max

@Max:仅用x作一般示例,我倾向于使用描述性很强的变量名。
用户

@User当然,我不认为这是一个真实的例子;)
Max

14

异议!加载的问题。

您能向我解释为什么其中包含第三代码??,而第一和第二代码却没有吗?为了公平起见,您的代码必须如下所示:

for(std::vector<T>::iterator it = x.begin(); it != x.end(); i++)
{
   it->???
}

for(std::map<T>::iterator it = x.begin(); it != x.end(); i++)
{
   it->second->???
}

那里。即使您没有使用,也会遇到同样的问题auto

在所有情况下,答案都是相同的:上下文很重要。您不能孤立地有意义地谈论一段代码。即使您没有使用模板,而是使用某种具体类型,这也只会将问题转移到其他地方,因为您的代码阅读者必须知道该类型的声明。

如果auto在这种情况下使用代码会使您的代码不可读,则应将其视为警告标志,表明代码设计有问题。当然,在某些情况下,低级细节很重要(例如,在处理位操作或旧式API时),在这种情况下,显式类型可能有助于提高可读性。但总的来说-不。

关于var(因为您已经明确提到了它),在C#社区中对于使用也有广泛的共识。反对使用它的争论通常基于谬误var


1
我认为关键是,使用auto时,您不知道接下来要放什么...是特定于代码的“东西”,还是与数据类型相关的解压缩才能到达具有“东西”方法的数据对象
Michael Shaw 2015年

1
@Ptolemy而我的观点是:在其他两个代码,你不懂(一般)把下一步:T是不透明给用户auto。但是一个应该还可以,而另一个不可以吗?那没有道理。对于OP,T是任意类型的替身。在实际代码中,可能是使用模板(for typename std::vector<T>::iterator…)或类接口。在这两种情况下,实际的类型对用户都是隐藏的,但是我们通常会编写此类代码而不会出现问题。
康拉德·鲁道夫

1
其实,是的。如果它是向量,则表明您需要执行->然后可以访问您的数据类型。如果它是地图,则您需要执行-> second->,然后就可以访问您的数据类型,如果它是自动的,则不知道需要执行什么操作才能访问您的数据类型。您似乎将“ STL集合中包含的数据类型是什么”与“我们拥有哪种STL集合类型”混淆了。汽车使这个问题变得更糟。
萧伯纳

1
@Ptolemy使用时,所有这些参数都是正确的autox从上下文中查看哪些操作支持是微不足道的。实际上,该类型不会为您提供任何附加信息:在两种情况下,您都需要一些辅助信息(IDE,文档,知识/内存)来告诉您所支持的操作集。
康拉德·鲁道夫

1
@Ptolemy也就是说只有当你在非常错综复杂的情况,你不知道什么是真正的begin回报,但你知道什么std::vector<>::iterator是。而且,您需要使用一个错误的编程工具,而该工具无法简单地为您提供此信息。这是非常令人费解的。在现实中,你要么知道这两个beginiterator或两者都不是,你应该使用一个IDE或编辑器,可以很容易地向您提供相关的信息。每个现代的IDE和编程编辑器都可以做到这一点。
康拉德·鲁道夫

11

专业版

您的代码:

for(std::vector<T>::iterator it = x.begin(); it != x.end(); i++)

由于模板相关的名称,将不进行编译。

这是正确的语法:

for( typename std::vector<T>::iterator it = x.begin(); it != x.end(); i++)

现在看看类型声明有多长时间。这说明了为什么auto引入了关键字。这个 :

for( auto it = x.begin(); it != x.end(); i++)

更简洁。所以,这是一个专业人士。


骗子

你要小心点 使用关键字auto,可以得到声明的类型。

例如 :

std::vector< int > v{ 1, 2, 3, 4 };
for ( auto it : v )
{
  ++ it;   // ops modifying copies of vector's elements
}

std::vector< int > v{ 1, 2, 3, 4 };
for ( auto & it : v )   // mind the reference
{
  ++ it;   // ok, vector's elements modified
}

结论:是的,您应该这样做,但不要过度使用它。有些人倾向于过多使用它,并把auto放在任何地方,例如下一个示例:

auto i = 0;

int i = 0;

auto i = 0。有罪。我做 但这是因为我知道那0是type的文字int。(和一个八进制常量;
Laurent LA RIZZA

6

是的你应该!auto不删除类型;即使您“不知道”什么x.begin(),如果您尝试错误使用该类型,编译器也会知道并会报告错误。同样,map用进行仿真也很常见vector<pair<Key,Value>>,因此使用的代码auto将对两种字典表示形式均适用。


4

是的,您应该使用auto默认规则。与显式指定类型相比,它具有原始优势:

  • 它不会使您键入编译器已经知道的内容。
  • 它使变量的类型“跟随”返回值类型的任何更改。
  • 这样做可以防止隐式转换的隐式引入和局部变量初始化中的切片
  • 它消除了模板中某些显式类型计算的需要。
  • 它消除了使用长名称命名返回类型的需要。(您从编译器诊断程序中复制粘贴的代码)

这是您可以选择的地方。在某些情况下,您别无选择:

  • 它允许声明不可言类型的变量,例如lambda的类型。

只要您确切知道该怎么auto做,它就没有缺点。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.