最近准备完整刷一遍《C++ Primer》,本文是记录的一些小的知识点,包括指向指针的引用,auto与const或引用一起使用,复杂的数组声明,sizeof运算符。
指向指针的引用
1 | int i = 42; |
要理解r的类型到底是什么,最简单的办法是从右向左阅读r的定义。离变量名最近的符号(此例中是&r的符号&)对变量的类型有最直接的影响,因此r是一个引用。声明符的其余部分用以确定r引用的类型是什么,此例中的符号*说明r引用的是一个指针。最后,声明的基本数据类型部分指出r引用的是一个int指针。
auto与const或引用一起使用
编译器推断出来的auto类型有时候和初始值的类型并不完全一样,编译器会适当地改变结果类型使其更符合初始化规则。
使用引用其实是使用引用的对象,特别是当引用被用作初始值时,真正参与初始化的其实是引用对象的值。此时编译器以引用对象的类型作为auto的类型:
1 | int i = 0, &r = i; |
其次,auto一般会忽略掉顶层const,但把底层const保留下来,比如当初始值是一个指向常量的指针时:
1 | const int ci = i, &cr = ci; |
如果希望推断出的auto类型是一个顶层const,需要明确指出:
1 | const auto f = ci; // deduced type of ci is int; f has type const int |
还可以将引用的类型设为auto,此时原来的初始化规则仍然适用:
1 | auto &g = ci; // g is a const int& that is bound to ci |
设置一个类型为auto的引用时,初始值中的顶层常量属性仍然保留。如果我们给初始值绑定一个引用,则此时的常量就不是顶层常量了(对常量的引用只能是底层常量,引用不存在顶层常量)。
复杂的数组声明
数组与指针或引用一起使用:
1 | int arr[10]; |
从数组的名字开始,按照“由内到外”的顺序来理解数组声明的含义。
多维数组:
1 | int ia[3][4]; |
sizeof运算符
sizeof运算符返回一条表达式或一个类型名字所占的字节数。sizeof运算符满足右结合律,所得的值是一个size_t类型。
加入油表达式expr,则使用:
1 | sizeof expr ; |
来获取表达式expr结果的大小时,并不会实际计算该表达式。
对于解引用的指针类型sizeof *p (等价于 sizeof(*p)),并不会真正地对指针解引用,即使是无效的指针,也同样可以求出大小。
c++11允许使用sizeof配合作用域运算符来获取类的成员并求它的大小。
sizeof运算符的结果部分地依赖于其作用的类型:
- 对
char或者类型为char的表达式执行sizeof运算,结果得1。 - 对引用类型执行
sizeof运算得到被引用对象所占空间的大小。 - 对指针执行
sizeof运算得到指针本身所占空间的大小。 - 对解引用指针执行
sizeof运算得到指针指向的对象所占空间的大小,指针不需有效。 - 对数组执行
sizeof运算得到整个数组所占空间的大小,等价于对数组中所有的元素各执行一次sizeof运算并将所得结果求和。注意,sizeof运算不会把数组转换成指针来处理。 - 对
string对象或vector对象执行sizeof运算只返回该类型固定部分的大小,不会计算对象中的元素占用了多少空间。
因为执行sizeof运算能得到整个数组的大小,所以可以用数组的大小除以单个元素的大小得到数组中元素的个数:
1 | int arr[10]; |