大家好,我是小康,一个在 C++ 的坑里摸爬滚打了 8 年的开发者。今天我要和大家聊聊那些让每个程序员都头疼的指针错误。
写了这么久C++,指针还是经常让你头大?代码莫名其妙崩溃,调试半天发现是指针出问题?面试官随便问个指针问题就把你问懵了?
放心,不是你一个人!今天我们就用最通俗的语言,聊聊 C++ 指针那些"坑"。
记得我刚开始学习的时候,光是看到 int *p 这样的代码就觉得脑袋瓜子嗡嗡的。但是,指针这个东西吧,就像自行车,一旦掌握了要领,那骑起来就是享受!今天我就把这些年踩过的坑都给大家分享出来,保证说人话,不说教科书!
错误一:野指针-这是个没拴绳的野狗啊!
这就好比你养了条狗,但是没给它栓绳子,它想跑哪跑哪,最后把邻居家的花园给祸祸了...
正确做法是啥? 要么给它一个合法的地址,要么直接给 nullptr:
错误二:忘记删除堆内存 - 这是在浪费资源啊!
这就像你上厕所占了个坑,但是用完不冲水就走了,后面的人都没法用了。正确的做法是:
更好的办法是直接用智能指针,这就相当于给厕所装了个自动冲水装置:
错误三:解引用空指针 - 这不是自己给自己挖坑吗?
在使用指针之前,一定要检查:
错误四:delete指针后继续使用 - 这是在玩火啊!
这就像你退了房租,但还硬要住在人家房子里,这不是找打吗?
正确做法:
错误五:数组使用单个delete删除 - 这是在瞎捣乱啊!
数组要用delete[ ]:
错误六:指针运算越界 - 这是要翻车的节奏!
正确做法:
错误七:返回局部变量的指针 - 这是在玩火!
这就像你要借别人的东西,但是人家已经搬家了,你上哪借去?
正确做法:
错误八:指针类型不匹配 - 强扭的瓜不甜啊!
正确做法:
错误九:多重指针不打基础 - 这是在叠积木不打底!
正确的搭法:
记住:多重指针就像搭积木,得从底层开始,一层一层稳妥地往上搭,跳着搭就容易倒塌!
错误十:const 和指针的位置摆错 - 这是在挖坑自己跳啊!
最常见的三种指针和const组合:
常见错误:
记忆技巧:
- const int* : const 在 * 左边,锁住值
- int* const : const 在 * 右边,锁住指向
- 要保护数据不被改,就用 const int*
错误十一:构造函数漏初始化指针 - 这是在埋定时炸弹啊
正确做法:
错误十二:函数参数传递指针没声明const - 这是在裸奔啊!
正确做法:
记住:只是读数据不修改时,一定要加const!不加const就像把数据扔在大马路上,谁都能改。
错误十三:指针移动导致内存释放失败 - 这是在玩火!
正确做法:
错误十四:指针和引用混用 - 这是在给自己找麻烦!
更清晰的做法:
错误十五:不安全的指针向下转换 - 这是在蛮干啊!
正确做法:
错误十六:函数指针调用前未检查 - 这是在冒险啊!
正确做法:
错误十七:在类里 delete this 指针 - 简直是自杀!
正确的做法:
记住:
- 在类的方法里删除 this指针就像自杀,死了还想干活那肯定不行
- 对象的生命周期最好交给外部代码或智能指针管理
- 如果非要在类里面删除自己,那删完就立即返回,别做其他操作
错误十八:智能指针互相引用 - 这是在手拉手绕圈圈!
循环引用示例:
正确的做法:
记住:
- 两个对象用shared_ptr互相引用,就像两个人死死拉住对方的手不放,谁都走不了
- 要解决这个问题,让一方改用weak_ptr,就像轻轻牵手就好,需要的时候随时可以松开
- 智能指针循环引用会导致内存泄漏,就像两个人一直拉着手,永远不能回家
注意:智能指针的循环引用很容易把人绕晕,我用两张手绘小图,带大家一步步理解这个过程:
循环引用图解:
说明:智能指针对象 tom 和 jerry 的引用计数值 count 都变成 2,导致在 main 程序退出时,各自的 count 都无法减为 0 ,从而造成内存泄漏。
使用 weak_ptr 避免循环引用:
说明:tom 和 jerry 的引用计数值 count 始终都是 1,main 程序退出时,各自的 count 都减到 0 ,内存正常释放。
错误十九:指针成员的深浅拷贝 - 很容易翻车!
正确做法:
人人都知道要深拷贝,但实际写代码时很容易忽略,尤其是在类有多个指针成员时。现代 C++ 建议优先使用智能指针来避免这类问题。
错误二十:函数内修改指针实参 - 这是在玩障眼法!
正确做法:
记住:
- 函数参数是传值的,修改指针形参不会影响外面的指针
- 要修改外部指针,必须传入指针的指针
- 这个问题在做指针操作时特别常见,很多人都会犯这个错
实战小贴士
(1) 优先使用智能指针
(2) 指针安全法则
- 用完指针及时置空 nullptr
- 分配内存后立即考虑释放的时机和方式
- 涉及指针的函数,第一步就是检查指针是否为 nullptr
- 使用智能指针时,要注意循环引用
(3) 关于指针和引用的选择:
(4) 代码规范建议
总结
看完这些指针的坑,是不是觉得其实也没那么可怕?记住一点:指针就是个地址,搞清楚这个地址指向哪,什么时候有效,什么时候无效,基本就能避免大多数问题了。