现代C++学习笔记(4):auto的前世今生
Image (题图来自网络并做适当修改)
1
auto,是C++语言继承自C语言的第一个关键字。嗯,按字母顺序排名的话,它确实是第一个。
之所以这样说,是因为我的确拥有过一本关于C语言的大部头书籍,该书从头到尾完全就是按照字母顺序来组织编排的。标准C语言的所有关键字、函数、运算符、宏、头文件等内容全混到一起,只按字母进行排列,挨个列出并作介绍。这根本就不是教材,而是一本字典。在那个互联网还远没有普及的年代,手上缺乏其他教材,于是我竟然把这本书从头到尾一页不落地啃了下来,这奠定了我后来的C/C++语言基础。
我也曾听说有不止一位朋友,趁着假期按帮助文档中的列表,学习R语言base、stats、utils等包的所有函数,后来成了大牛。因此,对于计算机语言这件事,鼓励大家不妨趁着年轻,多下一些笨功夫,能受益终身。
说回到 auto,在C语言中,最初它用于变量定义,放在变量类型的前面,说明变量的存储模式。与它同类的还有另外三个,分别是:
auto int a; /* 自动变量 / register int r; / 寄存器变量 / static int s; / 静态变量 / extern int e; / 外部变量 */ 2
接下来,分别解释下这四种变量存储模式:
自动变量(auto):在C语言中,这样的变量定义,通常都要求写在函数体的开始,它编译成机器指令时,会成为堆栈控制的相关代码,即从堆栈中预留出空间,当做变量使用,一旦函数退出,由于堆栈的还原,会自动被释放掉。所以这种变量被称为“自动”变量。然而,因为绝大多数变量其实都是以这种方式存在的,所以为了简化,该“auto”关键字可以省略,就写成“int a;”,效果完全一样。于是,该关键字,成了可有可无的存在。
寄存器变量(register):这是与CPU指令集相关的,早期计算机及编程非常注重代码的运行效率,恨不得从每个牙缝里抠出哪怕一点点运行时间和存储空间。CPU内置有几个存放变量的单元,称为寄存器,其存取速度比内存快得多,内存中的数据,要进行计算,通常也会先拷贝到寄存器中,然后运算指令才能正确工作。为了优化,早期的C语言编译器,就会允许程序员自己指定某个变量强制使用寄存器,而不要放入内存,以此来手工提高程序运行效率。然而,随着编译器的升级,这种人工干预的方式已经显得非常没有必要,甚至有时候反而还会拖累效率。最终,这个关键字被淘汰在历史中。
静态变量(static):这种变量,在编译过程中,通常是会放入单独的一个数据段。程序一旦从磁盘读入内存,就会存在于内存中,而不像自动变量那样,是在函数调用的过程中,临时分配而得。因此,它的生存期覆盖了整个程序的运行过程,几乎永远不用担心变量会失效。而相应地,自动变量的生存期,只存在于其所在函数的调用阶段,函数运行结束,该变量就失效,这也是为什么不能把自动变量的地址作为函数的返回值传出,真要试图传出,只能通过拷贝变量的方式进行。注意,在这里,与 static 对应的关键字并不是 dynamic,而是 auto,大概是因为auto更好写吧,哈哈。
外部变量(extern):这个关键字的存在,是为了让不同的C/C++源文件(.c 或 .cpp)能够使用同一个变量。如果没有这个关键字,在不同的源文件中分别写了相同的变量名,则编译过程中,会给每个模块(源文件的编译结果)都分配一块该变量的空间。最后在把这些模块链接起来,生成最终可执行文件时,会因为变量名冲突而报错。extern会告诉编译器,这个变量已经在另一个模块中分配空间,当前这个模块中,就别分配了,以此来确保最终的链接正常。
在理解完上面一大段关于上古C语言的基础知识后,我们可以认识到,auto和register都已经被淘汰了。流传下来,至今仍在C和C++语言中可使用的,也就只剩下后面两种,static 和 extern。而在 C++的新标准中,既然auto已经早已毫无存在感,那不妨赋予它新的含义和用法。
3
下面,列举几个新标准中的auto的新用法,体会一下auto重生后的魅力:
一、迭代器类型的定义:
不用auto:
#include
二、新的for循环:
不用auto:
#include
不用auto: int foo(int x, int y) { return (x * y); } 使用auto: auto foo(int x, int y) -> int { return (x * y); }
注:本文首发表于“不靠谱颜论”公众号,并同步至本站。