C++中常见的未定义行为(UB)场景汇总
请列举C++中常见的未定义行为(Undefined Behavior)场景,包括数据竞争、越界访问、解引用空指针、修改const对象、整数溢出、二次delete、左移越位等,并给出避免策略。
回答
苦行僧
常见UB场景:
- 解引用空/悬空指针:
int* p = nullptr; *p = 1;或int* p = new int; delete p; *p = 1; - 越界访问:
int arr[5]; arr[5] = 0;或std::vector<int> v; v[0] = 1; - 数据竞争:多线程同时非原子读写同一变量。
- 整数溢出:有符号整数溢出(
INT_MAX + 1),无符号整数溢出是良好定义的(回绕)。 - 左移越位:移动位数≥类型位宽(
1 << 32在32位int上)。 - 二次delete:
delete p; delete p;或两次shared_ptr管理同一裸指针。 - 修改const对象:
const int x = 1; const_cast<int&>(x) = 2;(仅当原始对象非const时安全的)。 - 函数返回局部变量引用:
int& f() { int x; return x; } - 在析构函数中抛异常且不被捕获(C++11起默认noexcept)。
- 类型双关(type punning):通过
reinterpret_cast访问不同类型对象(除char*外)。
避免策略:
- 使用智能指针替代裸指针。
- 使用
at()替代operator[](越界抛异常)。 - 启用编译器警告(
-Wall -Wextra -Werror)和sanitizer(ASan/UBSan)。 - 使用静态分析工具(clang-tidy、PVS-Studio)。