- 常量类型与常量表达式
- 常量指针
- 常量引用
- 类型别名与类型自动推导
- 类型别名
- 类型自动推导
- 域与对象的生命周期
int main()
{
const int x = 3;
std::cout << x << 'n';
x = 6; // error: cannot assign to variable 'x' with const-qualified type 'const int'
}
常量x在初始化的时候完成了写操作,之后x的生命周期内,再也不能进行写操作了。
对变量的读和写,是对内存的读和写,所以是有底层硬件支持的。但是常量没有硬件支持,它是由编译器来保证的。定义一个常量,如果常量错,编译器就会报错。
在底层常量和变量都是对应一块内存,但是如果定义了常量,当要写操作常量时,那么编译器就会报错。
为什么要使用常量呢,为什么要防止写操作呢。编译器会防止非法操作。
还有就是常量可以优化程序逻辑。
如果确定一个变量声明后,不会再被修改,就把它设置成常量。
常量指针:如果一个指针的const,那么表明这个指针只能指向定义的变量,不能指向其他。
int main()
{
int x = 4;
int* const ptr = &x; // ptr只能指向x,不能在指向其他变量
int y = 5;
ptr = &y; // error: cannot assign to variable 'ptr' with const-qualified type 'int *const'
}
注意,上面const如果在int后面,是限制指向的对象不能修改。但是如果const在int之前,就是限制指向的对象的内容不能修改。
int main()
{
int x = 4;
const int* ptr = &x;
x = 5;
std::cout << x << 'n'; // 5
*ptr = 10; // error: read-only variable is not assignable
int y = 10;
ptr = &y;
std::cout << *ptr << std::endl; // 10,ptr指向对象的内容不能发生改变,但是可以改变指向的对象
}
记忆方法,如果const在*的右边,那么ptr本身不能改变,也就是不能改变指向的对象。
如果const在*的左边,那么ptr指向的内容不能改变。
顶层常量,只是限制指针本身(指向的对象)不能修改。底层常量,限制指向指向的内容不能修改。
int main()
{
int x = 3;
const int& ref = x;
}
常量引用主要用于函数的形参
常量引用放在形参,主要是因为Str的复制成本高,如果形参是一个int或者其他内置类型,那么常量引用,变得画蛇添足。
#include#define constexpr const int main() { constexpr int y = 3; }
constexpr const int* ptr等价于在底层和顶层都是const。
比较旧的类型别名的引用:
typedef int Myint;
int main()
{
Myint x = 3;
}
新的类型别名的引用:
using Myint = int;
int main()
{
Myint x = 3;
}
老师推荐用using,不用typedef。
注意类型别名与指针的关系,当我们用类型别名定义一个指针的时候,应将指针的类型别名视作一个整体,那么这个指针是一个常量,而不是指针指向的内容是一个常量。
典型的类型退化,int引用退化成int。cpp内建数组会退化成指针。auto会产生退化,
#include#include int main() { auto x = 3; // 1 x是int类型 std::cout << std::is_same_v << std::endl; const auto y = 100; // 0 y是const int类型 std::cout << std::is_same_v << std::endl; }
x是const int,但是当x放在=右边时,会退化成int。
decltype和auto的区别,decltype不会产生类型退化。
#include#include int main() { int x = 3; int& y1 = x; auto y2 = y1; decltype(y1) y3 = y1; // 1 y2是int类型 std::cout << std::is_same_v << std::endl; // 1 y3是int引用 std::cout << std::is_same_v << std::endl; }
decltype如果是左值,会自动加上一个引用。
decltype里面是一个变量名称,那么一定会推到成这个变量。
#include#include int main() { decltype(3.5 + 15l) x = 3.5 + 15l; // 等价于下面的,c++14 decltype(auto) y = 3.5 + 15l; }
auto替换成等号右边,在进行计算。
域与对象的生命周期
一个程序可以划分为若干个域。
不属于函数和类,在最外面,就是全局域。
大括号限定的域,就是局部域。
系统会优先选择局部域。
生命周期,起始于初始化,终止于被销毁。



