13
常见坑与最佳实践
Pitfalls
现代 C++ 的坑比老 C++ 少多了,但下面这些 still 高发。
坑 1:浅拷贝导致 double free
类里有裸指针成员,又没写拷贝构造,默认浅拷贝让两个对象指向同一块堆内存,析构时释放两次。解法:用智能指针当成员,直接触发零法则,别自己管裸指针。
坑 2:悬垂引用 / 悬垂指针
函数返回了局部变量的引用或指针——局部变量函数一结束就销毁,你拿着的是块"已销毁"内存的引用。记住:别返回局部变量的地址/引用。
坑 3:迭代器失效
对 vector 做 push_back 触发扩容后,原来的迭代器全部失效,再去解引用就是未定义行为。遍历中删除元素要小心,用 erase 的返回值接新迭代器。
坑 4:智能指针循环引用
两个对象互相 shared_ptr 指向对方,引用计数永不归零,内存泄漏。弱的一方用 weak_ptr。
坑 5:忘记 override,多态静默失效
你想重写父类虚函数,但函数签名写错了(比如 const 漏了),编译器当成"新函数",多态悄悄不生效,运行结果诡异却不报错。永远加 override——签名一旦写错编译器当场喊你。
坑 6:有符号整数溢出是未定义行为
int 溢出在 C++ 里是 UB(undefined behavior),编译器会据此"合理优化"出你意想不到的结果。别指望它溢出后还按补码老老实实算。需要溢出就用无符号类型或加边界判断。
坑 7:模板报错信息看不懂
模板出错时,编译器能甩出几十行带尖括号的天书。诀窍:看报错最后一屏里"note"和你自己的文件名那几行,前面那堆是模板展开过程。C++20 concepts 出现后这类报错友好多了。
记
现代 C++ 生存守则
① 一律用 STL 和智能指针,手写裸 new/delete 是上一代的事。
② 重写虚函数必加 override;基类有虚函数就给虚析构。
③ 大对象传参用 const&;能 auto 推导就别手写长类型。
④ 编译开 -Wall -Wextra -Wpedantic,警告当错误。