C++中的未定义行为(Undefined Behavior)有哪些?(常见陷阱)

13次阅读

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

C++中的未定义行为(Undefined Behavior)有哪些?(常见陷阱)

未定义行为(UB)不是“随机出错”,而是标准完全不管后果——编译器可以优化掉、生成任意代码、崩溃、静默出错,甚至看似正常运行。它不报错、不警告(除非你开了严格检查),但一旦触发,程序逻辑就不可信。

访问越界的数组或指针

数组下标超出声明范围,或指针算术越过对象边界,都是典型 UB。哪怕只是读取(比如 a[5] 访问长度为 5 的数组),也不行。

  • int a[5] = {}; a[5] = 0; —— 写越界,UB
  • int* p = &a[0]; *(p + 5); —— 读越界,UB(即使没解引用,p + 5 本身已越界)
  • std::vector v(3); v.data()[5]; —— 同样 UB,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 运行时检测,比靠经验更可靠。

text=ZqhQzanResources