现代 C++ 编程实战
吴咏炜
前 Intel 资深软件架构师
34196 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 51 讲
加餐 (1讲)
现代 C++ 编程实战
15
15
1.0x
00:00/00:00
登录|注册

02 | 自己动手,实现C++的智能指针

函数模板
smart_ptr类
shared_count类
模板代码
移动赋值函数
移动构造函数
拷贝构造和赋值实现
禁用拷贝构造和赋值
成员函数
类模板
指针类型转换
引用计数
子类指针向基类指针的转换
"移动"指针
拷贝构造和赋值
模板化和易用性
智能指针基本功能
课后思考
实现C++的智能指针
上次总结后续的文章
上次总结结果
C++智能指针
总结

该思维导图由 AI 生成,仅供参考

你好,我是吴咏炜。
上一讲,我们描述了一个某种程度上可以当成智能指针用的类 shape_wrapper。使用那个智能指针,可以简化资源的管理,从根本上消除资源(包括内存)泄漏的可能性。这一讲我们就来进一步讲解,如何将 shape_wrapper 改造成一个完整的智能指针。你会看到,智能指针本质上并不神秘,其实就是 RAII 资源管理功能的自然展现而已。
在学完这一讲之后,你应该会对 C++ 的 unique_ptrshared_ptr 的功能非常熟悉了。同时,如果你今后要创建类似的资源管理类,也不会是一件难事。

回顾

我们上一讲给出了下面这个类:
class shape_wrapper {
public:
explicit shape_wrapper(
shape* ptr = nullptr)
: ptr_(ptr) {}
~shape_wrapper()
{
delete ptr_;
}
shape* get() const { return ptr_; }
private:
shape* ptr_;
};
这个类可以完成智能指针的最基本的功能:对超出作用域的对象进行释放。但它缺了点东西:
这个类只适用于 shape
该类对象的行为不够像指针
拷贝该类对象会引发程序行为异常
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入介绍了C++智能指针的实现原理和技术特点。首先,通过模板化和易用性的改进,将智能指针改造成一个类模板,使其能够包装任意类型的指针。其次,讨论了拷贝构造和赋值的问题,提出了禁止拷贝和转移指针所有权的解决方案。接着,介绍了如何利用“移动”来改善智能指针的行为,使其更加自然和灵活。最后,讨论了子类指针向基类指针的转换,通过增加模板代码实现了这一行为。文章通过实际代码示例和讲解,深入浅出地介绍了智能指针的实现原理和技术特点,对读者理解C++智能指针具有很好的指导意义。文章还介绍了引用计数智能指针的实现,以及指针类型转换的实现,为读者提供了完整的代码示例和实践应用。文章内容丰富,涵盖了智能指针的核心概念和实际应用,对于想深入了解C++智能指针的读者具有很高的参考价值。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《现代 C++ 编程实战》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(184)

  • 最新
  • 精选
  • frazer
    有点吃力了,得反复看几遍

    作者回复: 没关系。我打赌你看的时间肯定没我写稿的时间长。😁

    2019-11-26
    4
    108
  • yuchen
    有深度的专栏,不错。市面上讲解C++的课程一般太基础了。这一章推荐读者可以看看《Professional C++ 4th edition》第九章。

    作者回复: 谢谢。 《Professional C++》之前没看过,扫了两眼,觉得内容不错,推荐。内容还挺多挺深的,适合决心在 C++ 上深入的同学。

    2019-11-26
    5
    34
  • 皓首不倦
    请问下老师smart ptr 的拷贝构造函数为什么有一个泛型版本 还有一个非泛型版本 但是函数体内容又一模一样 不是代码冗余的吗 是有什么特殊设计意图吗 请老师指教下

    作者回复: 这是一个很特殊的、甚至有点恼人的情况。如果没有非泛型版本,编译器看到没有拷贝构造函数,会生成一个缺省的拷贝构造函数。这样,同样类型的smart_ptr的拷贝构造会是错误的。“子类指针向基类指针的转换”这一节里我也提到了这点。这不是我讲智能指针想讲的内容,所以就淡化了。

    2019-11-30
    4
    32
  • 流浪地球
    老师您好,问一个比较基础的问题,我理解这个语句 smart_ptr<shape> ptr1{create_shape(shape_type::circle)}; 是调用ptr1的拷贝构造函数。 为什么{create_shape(shape_type::circle)}是使用大括号,不应该是小括号吗? 谢谢

    作者回复: 嘻嘻,我在偷偷地塞进C++11的语法。对象初始化可以统一用大括号。(小括号这儿也行。)

    2019-11-26
    5
    30
  • NEVER SETTLE
    老师这块没想明白 // 1、调用构造函数 smart_ptr ptr1{create_shape(shape_type::circle)}; // 2、因为拷贝构造被禁用,随意编译出错 smart_ptr ptr2{ptr1}; // 编译出错 smart_ptr ptr3; // 3、没明白为啥会出错 ptr3 = ptr1; // 编译出错 // 4、没明白为啥OK,=重载函数的参数不是右值引用呀 ptr3 = std::move(ptr1); // OK, 请老师指定 3 与 4

    作者回复: 3. 赋值需要一个对象(不是引用),因而在进入执行前就要引发一个构造。没有合适的构造函数可用。 4. 同样,要先构造。这回可以用右值引用的构造函数了。

    2019-11-27
    4
    26
  • yyfx
    "移动"指针部分有个问题。在使用模板泛化拷贝构造时,p2=p1编译通过,程序异常。测试发现,由于拷贝构造并没有被自动禁用导致。查了下资料,effective45条提到,member templates不影响语言规则,声明member templates用于泛化copy构造时,还需要声明正常的copy构造。

    作者回复: 多谢抓虫。正文已更新。 这也证明了,修改代码、没有完整测试,是极易招虫的啊……

    2019-11-28
    21
  • hdongdong123
    真的好难啊,呜呜呜

    作者回复: 一遍看不懂,就再看一遍。所有的代码自己试验一下。😀 学习无捷径。掌握 C++ 不是 30 个课时能解决的事情。一万小时理论对于任何复杂领域都是基本适用的。

    2019-11-27
    15
  • 贵子
    为什么shared_count类作为smart_ptr的内部类编译不过,而必须作为外部类呢?老师能解释一下吗?谢谢!

    作者回复: 移进去的话,smart_ptr<circle>::shared_count 和 smart_ptr<shape>::shared_count 成了两个完全不相关的类型,它们的指针(在不做强制类型转换时)也不能互相赋值,不好。

    2019-12-13
    2
    14
  • 总统老唐
    吴老师,关于如何使用移动改善了 auto_ptr 的行为,实现了与 unique_ptr 相近的语义,这里的“改善”是否应该这样理解: 1, 在没有引入右值引用和移动构造的情况下,构造的 auto_ptr 也能工作,但是会令用户困惑,当用户执行了语句 other_ptr = some_ptr 后,some_ptr 就为空了 2, 引入右值引用和移动构造后,用户要想用重载的 operator=,必须采用 other_ptr = std::move(some_ptr) 的方式,通过显示调用 std::move,让用户aware到 some_ptr 的内容已经被移动到 other_ptr 了,并且同时默认禁用了参数为左值引用的拷贝构造,导致 other_ptr = some_ptr 无法通过编译,就不会在使用时产生歧义了,这就是 unique_ptr 期望的语义

    作者回复: 对。 另外额外加一点,调用移动不一定靠 move。如果函数返回一个 unique_ptr 一样是自然的移动。

    2019-12-12
    2
    14
  • nullptr
    我一直在纠结那个拷贝赋值参数不是引用的问题,不是引用的话,会产生一次拷贝构造函数,所以已经增加了引用计数,接着进行简单的swap操作就ok了,读者需要思考这个问题,很多人会忽略

    作者回复: 是这样的。所以第3讲我把这个单独作为问题提出来了。

    2019-12-07
    11
收起评论
显示
设置
留言
99+
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部