const在指针声明中修饰紧邻它的部分:int const p修饰指针本身(地址不可变),const int p修饰所指值(值不可变),const int* const p二者均不可变。

const 在指针声明里到底修饰谁?
看 const 紧挨着谁,就修饰谁——这是唯一靠谱的判断依据。很多人靠“常量指针”“指针常量”这种中文词去记,结果越记越乱,因为中文描述本身就有歧义。
实操建议:
-
int* const p = &x;:const紧挨*,所以指针本身不可变(地址固定),但它指向的值可改 -
const int* p = &x;或int const* p = &x;:const紧挨int,所以指向的值不可变,指针本身可重新赋值 -
const int* const p = &x;:两边都有const,地址和值都不可变
为什么传参时经常写 const T* 或 const T&?
不是为了“显得规范”,而是告诉调用方:这个函数不会通过这个参数修改原始数据;同时让编译器帮你拦住意外的写操作。
常见错误现象:
立即学习“C++免费学习笔记(深入)”;
- 函数声明用了
void foo(int* p),但内部只读*p,却意外写了*p = 42;—— 调用方完全没防备 - 传入字面量或临时对象时,非
const引用会编译失败:foo(42)对void foo(int&)不合法,但对void foo(const int&)合法
性能影响:引用和指针加 const 零成本,不改变生成代码,只影响类型检查。
const_cast 能不能用来“绕过 const”?
能编译,但绝大多数情况下是危险信号——尤其是当原始对象本身就是 const 时,强行改会导致未定义行为(UB)。
使用场景极少,仅限于对接旧 C API 或某些特殊封装逻辑,且必须确保底层对象实际可写:
- 原始变量声明为
const int x = 10;→ 用const_cast改x是 UB - 函数参数是
const int* p,但你知道它指向的是一个非常量变量 → 可以谨慎用const_cast,但要自己担责 - 标准库容器迭代器常提供
const_iterator,转成普通迭代器也得用const_cast(但更推荐用begin()而非cbegin())
constexpr 指针和 const 指针有什么区别?
const 是运行期不可修改语义;constexpr 是编译期必须确定值,约束更强。
关键差异:
-
constexpr int* p = &x;:要求p的值(即地址)在编译期可知,且x必须是静态生命周期对象(如全局变量、static 局部变量) -
const int* p = &x;:只要求运行时p不被重新赋值,x可以是栈上变量 -
constexpr const int* p = &x;:既要求指针本身编译期确定,又要求它指向的值是const(即不能通过p改*p)
容易踩的坑:局部非 static 变量的地址永远无法用于 constexpr 指针初始化,编译直接报错 error: address of local variable 'x' is not a constant expression。










