3.4.8 定制删除器
在3.4.2小节,我们特意没有讨论shared_ptr一种形式的构造函数shared_ptr(Y * p, D d),它涉及shared_ptr的另一个重要概念:删除器。
shared_ptr(Y * p, D d)的第一个参数是要被管理的指针,它的含义与其他构造函数的参数相同。而第二个删除器参数d则告诉shared_ptr在析构时不是使用delete来操作指针p,而要用d来操作,即把delete p换成d(p)。
在这里删除器d可以是一个函数对象,也可以是一个函数指针,只要它能够像函数那样被调用,使得d(p)成立即可。对删除器的要求是它必须是可拷贝的,行为必须也像delete那样,不能抛出异常。
为了配合删除器的工作,shared_ptr提供一个自由函数get_deleter(shared_ptr<T> const & p),它能够返回删除器的指针。
有了删除器的概念,我们就可以用shared_ptr实现管理任意资源。只要这种资源提供了它自己的释放操作,shared_ptr就能够保证自动释放。
假设我们有一组操作socket的函数,使用一个socket_t类:
- class socket_t {...}; //socket类
- socket_t* open_socket() //打开socket
- {
- cout << "open_socket" << endl;
- return new socket_t;
- }
- void close_socket(socket_t * s) //关闭socket
- {
- cout << "close_socket" << endl;
-
- //...其他操作,释放资源
- }
那么,socket资源对应的释放操作就是函数close_socket(),它符合shared_ptr对删除器的定义,可以用shared_ptr这样管理socket资源:
- socket_t *s = open_socket();
- shared_ptr<socket_t> p(s, close_socket); //传入删除器
在这里删除器close_socket()是一个自由函数,因此只需要把函数名传递给shared_ptr就可以了。在函数名前也可以加上取地址操作符&,效果是等价的:
- shared_ptr<socket_t> p(s, &close_socket); //传入删除器
这样我们就使用shared_ptr配合定制的删除器管理了socket资源。当离开作用域时,shared_ptr会自动调用close_socket()函数关闭socket,再也不会有资源遗失的担心。
再例如,对于传统的使用struct FILE的C文件操作,也可以使用shared_ptr配合定制删除器自动管理,像这样:
- shared_ptr<FILE> fp(fopen("./1.txt","r"), fclose);
当离开作用域时,shared_ptr会自动调用fclose()函数关闭文件。
shared_ptr的删除器在处理某些特殊资源时非常有用,它使得用户可以定制、扩展shared_ ptr的行为,使shared_ptr不仅仅能够管理内存资源,而是成为一个"万能"的资源管理工具。