未定义行为(UB)指标准完全不约束后果,编译器可任意优化、崩溃或静默出错;典型场景包括数组/指针越界、空指针或悬垂指针解引用、二次释放、有符号整数溢出等。

未定义行为(UB)不是“随机出错”,而是标准完全不管后果——编译器可以优化掉、生成任意代码、崩溃、静默出错,甚至看似正常运行。它不报错、不警告(除非你开了严格检查),但一旦触发,程序逻辑就不可信。
访问越界的数组或指针
数组下标超出声明范围,或指针算术越过对象边界,都是典型 UB。哪怕只是读取(比如 a[5] 访问长度为 5 的数组),也不行。
-
int a[5] = {}; a[5] = 0;—— 写越界,UB -
int* p = &a[0]; *(p + 5);—— 读越界,UB(即使没解引用,p + 5本身已越界) -
std::vector—— 同样 UB,v(3); v.data()[5]; data()不改变边界语义
解引用空指针或悬垂指针
空指针解引用是教科书级 UB;悬垂指针(指向已销毁对象的指针)解引用也一样危险,哪怕对象内存还没被覆盖。
-
int* p = nullptr; *p = 1;—— UB,哪怕某些平台“恰好”不崩溃 -
int* q; { int x = 42; q = &x; } *q;——x生命周期结束,q成悬垂指针,解引用即 UB -
delete p; delete p;或delete[] p;混用delete p;—— 二次释放或类型不匹配,UB
有符号整数溢出
C++ 标准只对无符号整数定义了模运算(自动回绕),而有符号溢出(如 int max + 1)是 UB —— 编译器可能据此做激进优化。
立即学习“C++免费学习笔记(深入)”;
-
int x = INT_MAX; x++;—— UB,不是“变成 INT_MIN” for (int i = 0; i 当n == INT_MAX时,i++必然溢出,UB- 用
unsigned int替代可规避(前提是业务允许回绕);否则应显式检查边界
未初始化的局部变量读取
非 static、非类成员的内置类型(int, double, 指针等)若未显式初始化,其值是“不确定的”,首次读取即 UB。
-
int x; return x * 2;—— UB,哪怕x碰巧是 0 -
int arr[3]; return arr[0];—— 同样 UB(arr是栈上未初始化数组) - 例外:static 或全局变量会零初始化;类成员若在构造函数中未显式初始化,也属 UB(除非是 POD 类型且定义了默认构造)
基本上就这些 —— 不复杂但容易忽略。开编译器警告(-Wall -Wextra -Wuninitialized)、用 AddressSanitizer 和 UBSan 运行时检测,比靠经验更可靠。










