- 1.类型别名与类型自动推导
- 1.1.类型别名
- 1.2.类型自动推导
- 2.域与对象的生命周期
-
比如size_t这种类型别名,它并不是一个新的类型,而是某种类型的别名。但是它一定是unsinged的类型,只不过长度不一样,有可能是unsigned int,也有可能是unsigned long,它是和具体的平台有关的,但是总之它所表示的类型返回一定是能够访问整个内存的。所以这个变量存在的意义就是为了防止定义变量的范围太小,不能足够访问整个内存。因此通常在for循环中使用size_t是更加规范的一种方式。
另外同样的类型别名还有in32_t,这个与size_t恰好相反,它是指定了在不同的机器平台上,类型的尺寸必须是32位,所以它可能是int类型,也有可能是long类型。 -
引入类型别名有两种方式,主要二者写法有所不同。typedef是原类型在前,类型别名在后;而using反过来,并且中间还要加一个=
-
使用using引入类型别名更加清晰。比如想引入一个char[4]的数组的类型别名,用typedef必须把[4]和char分开,显得非常奇怪,而使用using就没有这种问题。因此建议使用using来起类型别名。
-
给指针类型起类型别名的时候,需要把指针类型视为一个整体。也就是说类型别名并不是简单的宏定义的效果,它更像是真的有了一个“新的”类型,虽然这个“新的”类型本质上还是原有的类型。
using IntPtr = int*; int x = 0; // 下面的等价于int* const, 即const是修饰p1的,也就是一个指针常量 const IntPtr p1 = &x; // 正常的写法就是const int*, 即const是修饰int的,也就是一个常量指针 const int* p2 = &x;
- 不能通过类型别名构造引用的引用,二者的结果最终还是一个引用
using RefInt = int&; using RefRefInt = RefInt&; // 最终二者的结果都是int&类型1.2.类型自动推导
- 主要auto自动类型推导是需要初始化表达式的,因为只有有初始化的表达式才能根据表达式进行类型推导,从而给auto赋予真正的类型。如果没有初始化表达式自然无法推导。
// 正确 auto x = 3.5; // 错误 auto x; x = 3.5;
- auto产生类型退化的问题(注意引用也是一种类型)
- 退化实例1
int x = 3; int& ref = x; // 此时就是取ref(即x)的值赋值给y,所以ref从int&退化成int int y = ref; // 同理,如果这样写右侧的ref也是从int&退化成int, 结果ref2就是一个int整数, // 而不是一个引用 auto ref2 = ref;
- 退化实例2
// 正常 const int x = 3; const auto y = x; // x没有退化,还是const int类型 // 退化:右边的x退化成int类型,所以左边推导出来的就是int类型 auto y = x; // y是int类型
个人总结:感觉这个类型退化问题可以这样理解:对于实例2来说,x在右侧赋值的时候,相当于直接去x的内存里面取它存的数据,就是3,这个时候拿到的3和x本身是什么类型是没有关系的。所以左侧的auto就是对这个3进行类型的自动推导,找到一个最匹配的类型,所以就是int(好像也不太对?那为啥不是short/long/unsigned int?)。然后左边除了auto之外的那些限定符,仍然会保留,也就是只会自动推导auto,其他不会改变。
- auto&一定会推导出引用类型,避免类型退化
// 1.1.看到auto&一定会推导出引用类型,其次右边x不会进行类型退化,
// 所以最后y的类型就是const int&
const int x = 3;
auto& y = x;
// 1.2. 看到auto&一定会推导出引用类型,其次右边x不会进行类型退化,
// 但是auto还要匹配出一个最佳的类型,所以auto被推到成const int,
// 最后y的类型是const int&
const int& x = 3;
auto& y = x;
// 2.1.
int x[3] = {1, 2, 3};
auto x1 = x; // 类型退化,x1类型变成int*
// 2.2.
int x[3] = {1, 2, 3};
auto& x1 = x; // 不会产生类型退化,x1类型是int(&)[3]
- decltype也是自动类型推导,但是不会产生类型退化,感觉这个用法太高级了,一般不会用到。



