一、定制删除器的作用
定制删除器一般作用于shared_ptr和unique_ptr,当析构写死了delete的方式释放资源时,如果资源是new[]出来的(new数组),delete于new[]不匹配,会发生不可预知的错误,或者当资源是malloc出来的与delete也不匹配。所以要用定制删除器解决这个问题,这个定制删除器相当于仿函数,只需要当智能指针构造的时候同时传入仿函数(定制删除器即可)
1.1当没有定制删除器的时候析构写死的释放方式:
1.2当对象是new[]出来的或者是malloc出来的时候:
1.3程序运行:
1.4运行会报错,用库里的试试:
可以看出传了定制删除器后,针对不同的开辟资源的方式采用不同的释放方式,成功释放所有开辟出来的资源!
二、定制删除器的模拟实现
2.1设计思路
首先明白我们用定制删除器是用来解决单一的释放方式会带来不可预知的错误,这个定制删除器相当于仿函数,我们只需要构造智能指针的时候传入不同仿函数就可以实现不同的释放方式,当不传的时候默认是用delete来释放。
2.2设计
参考一下库是如何实现
显然是在类里的构造函数使用了模版,模版里增加了一个类型D,通过D构造一个对象del,再调用del来实现删除。通过传入D的类型来实现不同的删除方式。
代码:
当写到这里的时候你会发现,del肯定是用来初始化某个类成员变量,但这时候我的类成员变量里只有_ptr跟_pcout;所以要添加一个成员变量来接收D类型对象del的初始化,那么什么样的变量可以接收各种不同的可调用对象呢?(用A类举例)例:当传入定制删除器是仿函数的时候(DestroyArray<A>() )、当传入的定制删除器是lambda表达式的时候([](A*ptr){delete ptr;})、或者传入的是一个函数指针的时候(void(*p)(A*ptr));这时包装器就可以上场了,包装器格式:
function<返回类型(参数列表)>,上面这三个可调用对象的返回类型是void,参数列表是A*ptr都可以确定的,所以我们在成变量里可以添加一个包装器用来接收各种不同的可调用对象;
然后构造就可以接收del的初始化了:
然后析构就可以直接调用已初始化好的_delete来进行资源的释放:
运行:
运行还是报错,F10调试:
运行发现当我们调用sp1的析构的时候发生了报错,原来咱sp1构造的时候没有传入定制删除器,
然后成员变量也没给缺省,
当调用析构的时候编译器就无法调用_delete()
解决方法很简单,只要给_delete上默认缺省值就行
缺省值直接用lambda表达式设置成默认用delete方式释放即可;
再次运行:
成功了!