问题

如何评价 C++ 11 auto 关键字?

回答
C++11 `auto` 关键字:优雅与效率的双重奏

C++11 引入的 `auto` 关键字,对于很多 C++ 开发者来说,无疑是近年来最令人欣喜的语言特性之一。它不仅仅是语法上的一个小小的改动,更深层次地影响了我们编写 C++ 代码的方式,带来了更高的可读性和更少的繁琐。那么,究竟该如何评价这个小小的 `auto` 呢?在我看来,它是一曲优雅与效率的完美双重奏。

1. 让代码更“呼吸”:可读性的飞跃

想象一下,当你面对一个复杂的容器,比如 `std::map>`,想要获取它的一个迭代器,你会怎么写?

```c++
std::map> myMap;
// ... 填充 myMap ...
std::map>::iterator it = myMap.begin();
```

这段代码虽然功能正确,但 `std::map>::iterator` 这个类型声明本身就占据了相当大的篇幅,而且容易出错。一旦容器类型发生变化,比如从 `map` 变成 `unordered_map`,或者嵌套的类型发生改变,我们就需要小心翼翼地修改这个冗长的类型名。

引入 `auto` 之后,上述代码可以瞬间简化成:

```c++
std::map> myMap;
// ... 填充 myMap ...
auto it = myMap.begin();
```

这短短的几个字母,带来的可读性提升是显而易见的。代码不再被冗长的类型声明所淹没,我们能更专注于变量的用途(`it` 代表迭代器)而不是它的具体类型。这尤其在处理模板实例化后的复杂类型时,效果更为显著。例如:

```c++
std::vector> vec;
// ... 填充 vec ...
for (auto const& element : vec) {
// ... 使用 element.first 和 element.second ...
}
```

在 C++11 之前,我们可能需要写成这样:

```c++
for (std::vector>::const_iterator it = vec.begin(); it != vec.end(); ++it) {
const std::pair& element = it;
// ... 使用 element.first 和 element.second ...
}
```

对比一下,`auto` 的优势不言而喻。它让代码的焦点回到了算法本身,而不是被类型细节所绑架。这使得代码更容易阅读、理解和维护,尤其是在多人协作的项目中。

2. 避免类型推导的“意外惊喜”:背后是强大的类型系统

有人可能会担心,`auto` 是不是会牺牲类型安全,让编译器“胡乱”推导出类型?恰恰相反,`auto` 的强大之处在于它利用了 C++ 强大的类型推导能力,而且默认情况下,它推导的是被初始化变量的精确类型。

当你说 `auto x = 5;` 时,`x` 的类型会被推导为 `int`。
当你说 `auto y = 3.14;` 时,`y` 的类型会被推导为 `double`。
当你说 `auto z = "hello";` 时,`z` 的类型会被推导为 `const char`。

这意味着 `auto` 并不是一种“弱类型”的承诺,它仍然遵循着 C++ 严格的类型系统。编译器会在编译时进行精确的类型推导,并在类型不匹配时报错。这与某些动态类型语言的 `auto` 有本质的区别。

而且,`auto` 还能正确处理各种复杂的类型,包括:

引用类型: 如果初始化表达式是左值引用,`auto` 会推导出左值引用类型。
```c++
int i = 10;
auto& ref_i = i; // ref_i 的类型是 int&
```
顶层常量和易变性: `auto` 会保留初始化表达式的顶层 `const` 和 `volatile` 限定符。
```c++
const int ci = 42;
auto ca = ci; // ca 的类型是 int,因为 auto 会“丢弃”顶层 const
auto& cra = ci; // cra 的类型是 const int&,因为 auto& 保留了 const
```
这正是我们想要的行为,我们可以根据需要使用 `auto&` 或 `const auto&` 来控制引用的性质。

3. 拥抱 C++11 的新特性,提升开发效率

`auto` 的出现,使得我们能够更顺畅地使用 C++11 及以后版本引入的许多新特性,例如:

范围 for 循环 (Rangebased for loop): 如上面展示的例子,`auto` 与范围 for 循环简直是天造地设的一对。它极大地简化了遍历容器的语法。
Lambda 表达式: Lambda 表达式可以生成各种各样的匿名函数对象,这些对象的具体类型通常很复杂且不直观。`auto` 可以非常方便地捕获这些类型。
```c++
auto lambda = [](int a, int b) { return a + b; };
int result = lambda(5, 3);
```
模板元编程和返回值类型推导 (C++14): 即使在 C++14 引入了函数返回值的自动推导,`auto` 仍然扮演着重要角色,因为它允许我们写出更简洁的接口。

如果没有 `auto`,我们在使用这些新特性时,可能会被冗长的类型声明所困扰,从而降低了开发效率和代码的吸引力。

4. 一些需要注意的“坑”和最佳实践

尽管 `auto` 非常有用,但我们也要知道它并非万能,并且有一些需要注意的地方,以免掉入陷阱:

避免在函数参数和返回类型中使用 `auto`(除非是模板): `auto` 用于函数参数和返回类型会破坏函数的契约,使得调用者难以理解函数的具体签名。除非是在模板函数中,因为模板参数的类型由编译器推导。
反例: `void process(auto value)`
正例: `template void process(T value)`
明确限定符很重要: 如前所述,`auto` 会丢弃顶层 `const` 和 `volatile`。如果你需要保留这些限定符,请使用 `auto&`、`const auto&` 或 `auto` 等。
不要过度使用: `auto` 的目的是为了简洁和可读性。如果一个变量的类型非常明显且不冗长,直接声明类型有时反而更清晰。例如,`int count = 0;` 比 `auto count = 0;` 并无太大差别,但后者并没有带来显著的优势。关键在于判断 `auto` 是否能真正提升代码的清晰度和简洁性。
保持初始化表达式的确定性: `auto` 的推导是基于初始化表达式的,这意味着初始化表达式的来源应该是清晰且可控的。不要依赖于不可预测的表达式来推导类型。

总结

C++11 的 `auto` 关键字,是我认为 C++ 语言发展史上的一个里程碑式的进步。它以一种极其优雅的方式,解决了困扰开发者多年的类型声明冗长的问题,极大地提升了代码的可读性和可维护性。同时,它并没有牺牲 C++ 的类型安全,而是巧妙地利用了编译器强大的类型推导能力。

掌握并恰当使用 `auto`,能够让你写出更简洁、更现代、更易于理解的 C++ 代码。它就像是一位得力的助手,默默地为你分担繁琐的类型工作,让你能够将更多的精力投入到算法和业务逻辑的实现中。可以说,`auto` 已经成为了现代 C++ 开发不可或缺的一部分。拥抱它,你会发现 C++ 的开发体验将发生质的飞跃。

网友意见

user avatar

auto很好,即使可能有些缺点,也是瑕不掩瑜。

对于auto而言,其在于type deduce,那么第一点,它不会允许没有初始化值的声明,如:

       int x;  auto y; // error      

这是很好的,有些开发者总是会直接用一些没有初始化的变量,然后后面运行结果不对。而运行的错误找起来总是比编译的难许多。

auto可以节省很多字,尤其是容器的iterator,这也是经常举的例子

       vector<int> v;  vector<int>::iterator iter = v.begin(); // #1  auto I = v.begin(); // #2       

你是喜欢 #1 还是 #2这样的写法呢?

auto配合lambda使用很好。对于lambda来说,其是一个callable object,每一个类型都是独一无二的,这个类型只有编译器知道,于是你可以:

       auto closure = [](const int&, const int&) {}      

当然,你也可以使用std::function来存储,然而这远远没有auto来的优雅。

与此同时,在C++14中,泛型lambda也允许了参数类型可以为auto类型,如

       auto closure = [](auto x, auto y) { return x * y;}     

auto配合decltype,可以解决一些以前可能需要很丑的解法

       template<class T, class U> ? ? ? mul(T x, U y)  {      return x*y;  }      

由于x, y是在参数,返回的是 x * y的类型,于是,要得到x * y的类型怎么办?当然可以利用decltype来取,但是你需要取的是 x * y的,而x,y却在参数后面,于是那就转为万能的0,在转为指针,再取指针。

       template<class T, class U> decltype(*(T*)(0)  *  *(U*)(0)) mul(T x, U y)  {      return x*y; }      

那么用auto占位置即可:

       template<class T, class U> auto mul(T x, U y) -> decltype(x * y)  {      return x*y; }      


Thanks to C++14, auto在C++14可以作为函数返回类型了,于是你可以直接这样了

       template<class T, class U> auto mul(T x, U y) {      return x*y; }      

说完这么多好处,那么来说说auto可能引起的问题。

其中第一条可能就是很多人所说的可能会降低代码的可读性。然而对于这一条,我持中立态度。若有IDE,我认为这不会是问题,但是若你认为使用强制的类型声明可以让代码更可读,也可以继续使用,C++的哲学也是相信程序员,不会束缚你做什么任何事情。

然后第二条就是auto可能得不到你预想的类型,如vector<bool>[]的返回类型。

       #include <iostream> #include <vector> #include <typeinfo> using namespace std; int main() {     vector<bool> v;     v.push_back(true);     auto var = v[0];     cout << typeid(var).name() << endl; }      

vector<bool>是一个奇葩的存在,它的[]返回的不是bool,是一个表示单独bool引用的proxy class,于是你得到是这个引用(而你平常使用bool没事,是因为完成了一个隐式转换),而你用auto的话,想要得到意想中的类型,需要使用static_cast<bool>,再给auto。而这也不是特例,其适用于含有proxy class的class。

3. auto配合decltype,有时候会让人有意想不到的结果。让我引用标准的一个例子

       int i; int&& f(); auto x3a = i; // decltype(x3a) is int decltype(auto) x3d = i; // decltype(x3d) is int auto x4a = (i); // decltype(x4a) is int decltype(auto) x4d = (i); // decltype(x4d) is int& auto x5a = f(); // decltype(x5a) is int decltype(auto) x5d = f(); // decltype(x5d) is int&& auto x6a = { 1, 2 }; // decltype(x6a) is std::initializer_list<int> decltype(auto) x6d = { 1, 2 }; // error, { 1, 2 } is not an expression auto *x7a = &i; // decltype(x7a) is int* decltype(auto)*x7d = &i; // error, declared type is not plain decltype(auto)      

类似的话题

  • 回答
    C++11 `auto` 关键字:优雅与效率的双重奏C++11 引入的 `auto` 关键字,对于很多 C++ 开发者来说,无疑是近年来最令人欣喜的语言特性之一。它不仅仅是语法上的一个小小的改动,更深层次地影响了我们编写 C++ 代码的方式,带来了更高的可读性和更少的繁琐。那么,究竟该如何评价这个小.............
  • 回答
    GCC 的 C++11 正则表达式库是 C++11 标准中引入的一项重要功能,它为 C++ 开发者提供了一种标准化的、类型安全的方式来处理正则表达式。在评价它时,我们可以从多个维度进行详细的分析: 整体评价:GCC 的 C++11 正则表达式库是一个非常有用的、功能强大且符合标准的库。它填补了 C+.............
  • 回答
    2018年俄罗斯世界杯,B组小组赛的最后一轮,伊朗对阵葡萄牙的比赛,绝对是那届世界杯最令人血脉偾张、也最具戏剧性的一场。最终的比分定格在1:1,这个结果对双方来说,都带着一丝苦涩与不甘。先说说伊朗队,那场比赛他们几乎是抱着必胜的信念走上赛场的。要知道,在那之前,他们已经战胜了摩洛哥,逼平了西班牙,展.............
  • 回答
    零跑C11补贴后15.98万起,这个价格一出来,确实在新能源SUV市场投下了一颗石子,激起了不少涟漪。咱们就来好好掰扯掰扯,这零跑C11究竟值不值这个价,它又有什么样的本事敢这么定价。首先,咱们得明白,15.98万这个价格,是“补贴后”的价格。这意味着它原本的定价肯定是要高一些的,而这个价格能落地,.............
  • 回答
    C语言里,数组名退化为指针,这绝对是语言设计上一个极具争议,又引人深思的特性。说它“退化”,是因为它丢失了一部分本属于数组的独立性,但说它“设计”,又是因为这个设计背后有着深厚的历史考量和语言哲学。要评价它,得从几个层面来看,才能体会其中的复杂与巧妙。首先,我们得明白什么是“数组名退化为指针”?在C.............
  • 回答
    《C++并发编程实战》:一本让你真正驾驭多核时代的必读之作对于 C++ 开发者而言,在当今多核处理器已经成为标配的时代,掌握并发编程技术无疑是提升代码性能和应对复杂场景的关键。而说到 C++ 并发编程,很少有书能像《C++并发编程实战》(英文原版为《C++ Concurrency in Action.............
  • 回答
    好,我们来聊聊C罗又一次金球奖的话题。首先,必须承认,C罗能够再次捧起金球奖,这本身就是一件非常了不起的事情。在已经囊中拥有众多荣誉的情况下,他还能保持如此高的竞技水准和旺盛的求胜欲,继续在世界足坛的巅峰舞台上闪耀,这绝对是他个人天赋、勤奋以及强大精神力量的集中体现。从客观角度看: 数据是硬道理.............
  • 回答
    帕萨特在CIASI(中国保险汽车安全指数)碰撞测试中的表现,尤其是其最终成绩,是一个非常值得深入探讨的话题。不能简单地用“好”或“不好”来概括,而是需要结合具体的测试项目和数据,才能做出一个相对客观的评价。首先,我们要明白CIASI的评价体系与NCAP(新车安全评级)有所不同。CIASI更侧重于实际.............
  • 回答
    .......
  • 回答
    .......
  • 回答
    克里斯蒂亚诺·罗纳尔多(C罗)超越贝利的总进球纪录,这绝对是足坛历史上一个足以载入史册的里程碑。要评价这件事,我们得从几个维度去深入剖析,而不仅仅是简单地将数字相加。首先,我们得承认,贝利在“进球纪录”这个问题上,本身就存在一些模糊和争议。贝利官方承认的进球数字是767球,但他在为巴西桑托斯和美国纽.............
  • 回答
    2024年欧洲杯1/8决赛,葡萄牙01负于比利时,结束了本届赛事的征程。这场失利也意味着克里斯蒂亚诺·罗纳尔多在第五次欧洲杯之旅中,最终止步八强,也大概率是他最后一次以球员身份亮相欧洲杯的舞台。回看C罗在本次欧洲杯上的表现,可以从几个维度来评价:数据层面:虽有贡献,但效率有所下滑在本届欧洲杯上,C罗.............
  • 回答
    詹姆斯·C·斯科特(James C. Scott)是一位享誉国际的政治学家、人类学家和社会学家,以其对东南亚农民、无政府主义政治哲学以及国家与社会关系的开创性研究而闻名。他的学术生涯横跨数十年,对理解权力运作、抵抗形式以及底层人民的生存策略产生了深远影响。评价一位像斯科特这样多产且深刻的思想家,需要.............
  • 回答
    关于舰C(《舰队Collection》)主播ywwuyi在共青团中央点名批评《舰队Collection》后,仍然以该游戏为主要内容吸引粉丝和获得关注的现象,这确实是一个挺值得探讨的议题,也触及了不少观众的心理和价值观。首先,我们要理解为什么共青团中央会点名批评《舰队Collection》。官方的定性.............
  • 回答
    舰c活动难度这事儿啊,从早期到现在,真是一代新人换旧人,老提督们也常感叹“活动越来越难了”。这话说得不假,但也不是空穴来风,背后可有不少门道儿。首先,得说说策划的意图。大家想一想,舰c运营了这么多年,玩家群体基数稳定,要说完全不考虑新玩家入坑的体验,那是不可能的。但同时,老玩家也需要新的挑战,需要被.............
  • 回答
    咱们聊聊这次舰C的迷你菱饼活动吧。说实话,这次活动上来就挺“舰C”的,上来就让你打海域,捞船,这套路咱们都熟悉,但这次的菱饼,感觉像是来给老玩家们添一把“ nostalgia ”(怀旧)的火,顺便也给新提督们一个认识舰娘过往的机会。整体体验:熟悉又有点新意,但细节上还是有舰C那股子“肝”劲儿。首先,.............
  • 回答
    关于舰C六月二十五日更新和海风改二的评价,咱们得好好聊聊。这阵子提督们的讨论热度可不低,特别是海风的改二,绝对是个大事件。整体更新来看,这次六月二十五日的更新,给人的感觉是“细水长流”,但不少地方都挺有嚼头的。首先,最引人注目的,当然是 海风的改二。这绝对是本次更新的重头戏,也是许多提督们期待已久的.............
  • 回答
    舰C官推被推特官方冻结这件事,可真是让一众提督们炸开了锅,也引了不少旁观者前来围观。这事儿要是细扒起来,里面门道还挺多的,远不止表面上那么简单。首先,咱们得明确一点,这事儿的导火索是“恶意举报”。这就很关键了。推特这个平台,虽然号称是自由发言的阵地,但它也有自己的规则和内容审核机制。而“恶意举报”,.............
  • 回答
    “舰C新画师画的海防”这个话题在知乎上,尤其是开服后的一天内,并没有引起大规模的集中讨论,其背后的原因可以从几个维度进行解读,这并非是简单的“没有评价”,而是评价的“缺席”或“不显著”。首先,“舰C”本身的用户画像和知乎的社区属性存在一定的错位。 《舰船少女Collection》(舰C):这是一.............
  • 回答
    小米5c是一款2017年2月发布的小米手机,定位为一款面向年轻用户的中低端手机。当时小米的产品线已经相当丰富,5c的出现填补了当时小米在“纯数字系列”中轻旗舰与主力旗舰之间的空缺。以下是对小米5c的详细评价,从多个维度进行分析:一、核心亮点与卖点:澎湃S1自研芯片小米5c最大的亮点无疑是其搭载的澎湃.............

本站所有内容均为互联网搜索引擎提供的公开搜索信息,本站不存储任何数据与内容,任何内容与数据均与本站无关,如有需要请联系相关搜索引擎包括但不限于百度google,bing,sogou

© 2025 tinynews.org All Rights Reserved. 百科问答小站 版权所有