C++ 指针常量与常量指针是什么?(如何正确使用 const 关键字)

3次阅读

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

C++ 指针常量与常量指针是什么?(如何正确使用 const 关键字)

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_castx 是 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

text=ZqhQzanResources