罗剑锋的 C++ 实战笔记
罗剑锋
前奇虎 360 技术专家,Nginx/OpenResty 开源项目贡献者
34779 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 32 讲
结束语 (1讲)
罗剑锋的 C++ 实战笔记
15
15
1.0x
00:00/00:00
登录|注册

08 | smart_ptr:智能指针到底“智能”在哪里?

你好,我是 Chrono。
上节课在讲 const 的时候,说到 const 可以修饰指针,不过今天我要告诉你:请忘记这种用法,在现代 C++ 中,绝对不要再使用“裸指针(naked pointer)”了,而是应该使用“智能指针(smart pointer)”。
你肯定或多或少听说过、用过智能指针,也可能看过实现源码,那么,你心里有没有一种疑惑,智能指针到底“智能”在哪里?难道它就是解决一切问题的“灵丹妙药”吗?
学完了今天的这节课,我想你就会有个明确的答案了。

什么是智能指针?

所谓的“智能指针”,当然是相对于“不智能指针”,也就是“裸指针”而言的。
所以,我们就先来看看裸指针,它有时候也被称为原始指针,或者直接简称为指针。
指针是源自 C 语言的概念,本质上是一个内存地址索引,代表了一小片内存区域(也可能会很大),能够直接读写内存。
因为它完全映射了计算机硬件,所以操作效率高,是 C/C++ 高效的根源。当然,这也是引起无数麻烦的根源。访问无效数据、指针越界,或者内存分配后没有及时释放,就会导致运行错误、内存泄漏、资源丢失等一系列严重的问题。
其他的编程语言,比如 Java、Go 就没有这方面的顾虑,因为它们内置了一个“垃圾回收”机制,会检测不再使用的内存,自动释放资源,让程序员不必为此费心。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结
仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《罗剑锋的 C++ 实战笔记》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(62)

  • 最新
  • 精选
  • Eglinux
    C++ 这么小众吗?讲得这么好,如果写成书,完全可以看成另外一本 effective C++ 了,为什么才 3000 多订阅人数?

    作者回复: 已经不少了吧,相识就是缘分,笑。

    3
    49
  • 酸葡萄
    老师,您好,什么时候用weak_ptr,什么时候用shared_ptr?

    作者回复: 我给一个不是很精确的评价标准吧。 shared_ptr是强引用,无论如何都需要持有共享对象的时候就用它。 weak_ptr是弱引用,不一定要持有对象,只是“偶尔”想去看看对象在不在,不在也可以接受。

    28
  • eletarior
    默认用的比较多的是unique_ptr ,相反的shared_ptr倒是用的不多,因为担心文中提到的循环引用,资源消耗,线程安全等问题。大部分时候,unique_ptr是能完全取代裸指针的。如果是存粹的标准C++代码,使用智能指针确实很舒服,把它们当成一个普通的类型看就行了。但是,同时,作为C++程序员我们又不得不和裸指针打交道,不论是Linux还是Windows,我们不可避免的要使用它们的系统api,于是就不得不使用get将智能指针转成裸指针。而这条指针所指向的内存在系统api里也许是不应该随意析构掉的,因为在系统内部可能还得继续使用这段内存,那么在这种场景下,智能指针的特性就可能帮倒忙,难受了😫。针对这种问题,我想到的就是延长这个智能指针的生命周期,或者直接使用release将裸指针释放出来,可是这样一来,delete就少不了要使用了😔

    作者回复: 是的,涉及到系统底层,有时候就可能要用到delete,不过你也可以试着用RAII来管理,或者用shared_ptr的定制删除函数,还是能够找到不用delete的方式的。

    2
    18
  • 颓废人才
    罗老师您好,还有一个问题,常用的C++ reference 我看到一个 cplusplus.com和cppreference.com, 但是网上有一些不好评价,觉得这两个网站都有问题,罗老师这边一般参考的哪些文档网站,可以推荐下么。非常感谢。

    作者回复: 我一般看的是cppreference.com,觉得它的界面比较好,资料组织整理的也很清楚,和官方标准基本吻合。 这些网站都是免费的,我觉得就可以一起看,互相参照。

    11
  • 禾桃
    “因为 shared_ptr 具有完整的“值语义”(即可以拷贝赋值)” 一直都觉得值语义这三个字比较难理解。想请教下这个概念到底是想说明什么问题,这个“值”该怎么理解?

    作者回复: 值是和引用对应的,值就是有实体,可以拷贝,而引用是虚的,只是个别名,操作上有区别。

    10
  • Luke
    使用智能指针可以自动析构“资源”,隐含了指针管理的细节,从而提高了代码的安全性和易用性,但是这是否同时意味着效率下降?在极致追求执行速度的系统中,是否需要避免使用智能指针,依赖程序员自己管理裸指针的new和delete呢?

    作者回复: 追求极致性能,那当然还是要自己管理好了,但这样也就要自己承担安全的责任了。 建议用unique_ptr,它的速度与裸指针几乎相同,没有引用计数的成本。

    6
  • 郭郭
    老师,关于unique_ptr,如auto ptr = ptr1,那ptr1就应该被置空啦。不需要显示的调用std::move

    作者回复: 我测试了一下,是不行的,会报编译错误,因为unique_ptr禁止了普通的拷贝赋值,只允许转移,必须调用std::move()。

    6
  • The Answer
    老师,shared_ptr 本身是线程安全的,但是如何理解它所管理的对象不是线程安全的呢?

    作者回复: shared_ptr就像是一个盒子,它自己是安全操作的,但一旦把里面的东西拿出来,就无法保证了。 shared_ptr和它指向的对象是彼此独立的,所以线程安全当然是没有关系的,shared_ptr只是一个handle,离开了handle,它就不能保证了。

    4
    5
  • Geek_王
    罗老师能把文中提到的血泪教训详细说一下吗?什么问题?怎么解决的?

    作者回复: 就是类的析构函数比较大,里面的操作很多,用shared_ptr来管理,由于析构的时机不确定,经常会发生莫名其妙的系统抖动,就像是java/go的gc stop the world一样。

    3
    4
  • Zivon
    罗老师,今天尝试使用智能指针改写双向链表的时候感觉实现很麻烦啊,请问在实现这种基本数据结构的时候需要使用智能指针吗

    作者回复: 基本的数据结构强调效率,用智能指针就有点成本略高,当然作为练手还是可以的。 智能指针最适合的应用场景是“自动资源管理”,链表还是不太合适,而且使用shared_ptr容易出现循环引用,改成weak_ptr会好一些。

    4
收起评论
显示
设置
留言
62
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部