定制删除器
我们在上面试验的代码全部都是new的单个元素 在这种环境下没有析构没有暴露出问题
可以一旦我们使用 new [] 情况就复杂起来了 如下图
假设A类定义出来的对象大小为20个字节 new五个对象 那么我们实际开辟的空间为64字节 前面四个字节会存放着我们开辟了对象的个数 (int类型存放)
那么此时我们就不能简单的调用delete了 我们还要考虑指针偏移的问题
这个时候就到我们的定制删除器上场了
其实呢 定制删除器的写法很简单
我们只需要在模板处加上这行代码
template<class T ,class D>
删除处加上这两行代码就可以
D del; del(_ptr);
不过这样子写有个小问题 就是以后的shared_ptr就必须要传入两个参数了
当然这个问题也可以解决 我们给他设置一个默认的模板参数 delete即可
template<class T> struct DELETE { public: void operator()(T* ptr) { delete ptr; } }; template<class T ,class D = DELETE<T>>
智能指针总结
为什么需要智能指针?
因为可能忘记释放资源造成内存泄漏
加上异常安全的原因 防不胜防
RAII机制是什么
英文是 Resource Acquisition Is Initialization
直译过来即为 资源请求后初始化
它是一种利用对象管理资源的思路 实际上将管理的责任托管给了对象
这种做法有两个好处
- 不需要显式地释放资源。
- 采用这种方式,对象所需的资源在其生命期内始终保持有效。
智能指针的发展历史
auto_ptr 到 bosst库中的三个智能指针 再到C++11中的三个智能智能
auto_ptr 在C++11被弃用 在C++17被彻底废除
auto_ptr unique_ptr shared_ptr weak_ptr的区别
前三个智能指针在RAII和模拟指针行为方面区别不大 主要区别在于拷贝方式
auto_ptr是一种不负责任的管理权转移
unique_ptr是简单粗暴的不准拷贝
shared_ptr则是引用计数
weak_ptr是shared_ptr的小跟班 来解决shared_ptr循环引用的问题
模拟实现一个智能指针
如果没有特殊要求我们优先实现unique_ptr 因为比较简单
如果有特殊要求那么一般就是实现shared_ptr了
这里比较难的主要是拷贝构造和赋值运算符重载的实现 下面给出实现代码
SmartPtr(const SmartPtr<T>& sp) :_ptr(sp._ptr), _pcount(sp._pcount) { (*_pcount)++; }
赋值运算符重载的注意点比较多
首先不能是自己给自己赋值 其次要想到赋值后原资源有没有消失
最后赋值的资源记得++
SmartPtr& operator=(const SmartPtr<T>& sp) { if (_ptr == sp._ptr) { return *this; } if (--(*_pcount) == 0) { delete _ptr; delete _pcount; } _ptr = sp._ptr; _pcount = sp._pcount; (*_pcount)++; return *this; }