最近准备完整刷一遍《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]; |