shared_ptr与删除器
2023年12月28日 2023年12月30日
删除器是一个可调用对象 deleter
使用内置指针初始化shared_ptr时, 为动态对象绑定删除器
删除器为可调用对象
1shared_ptr<T> sp(p, d);
示例
销毁动态对象时, 将内置指针传入删除器, 由删除器负责销毁动态对象
- 删除器的参数为内置指针类型
- 删除器负责销毁动态对象: 对指针指向delete运算
实际还是使用对象的析构函数销毁对象 - 删除器可以完成其他所需操作
删除器只对绑定的动态对象有效
1#include <iostream> 2#include <ostream> 3#include <string> 4#include <vector> 5#include <memory> 6 7using std::cout; 8using std::endl; 9using std::string; 10using std::ostream; 11 12class Foo 13{ 14 friend ostream &operator<<(ostream &os, const Foo &f); 15public: 16 Foo(string _name): name(_name) {} 17 ~Foo() { cout << "Call ~Foo for " << *this << endl << endl; } 18private: 19 string name; 20}; 21 22ostream &operator<<(ostream &os, const Foo &f) 23{ 24 os << f.name; 25 return os; 26} 27 28void DeleteFoo(Foo *f) 29{ 30 cout << "call " << __FUNCTION__ << " for " << *f << endl; 31 delete f; // 调用~Foo() 32} 33 34int main(int argc, const char * argv[]) { 35 Foo f("Kate"); 36 auto p = new Foo("Peter"); 37 std::shared_ptr<Foo> f2(p, DeleteFoo); // 为Peter绑定删除器 38 39 f2 = make_shared<Foo>("Mary"); // 为Peter调用删除器, 删除器调用析构函数 40 41 f2 = nullptr; // 为Mary调用析构函数 42 43 cout << "main finished.\n"; 44 return 0; 45} // main函数结束才为Kate调用析构函数
输出
call DeleteFoo for Peter Call ~Foo for Peter Call ~Foo for Mary main finished. Call ~Foo for Kate
善用shared_ptr机制: 使用删除器管理非动态对象
- shared_ptr指向非动态对象
- 销毁shared_ptr时,对管理对象调用删除器
示例
使用shared_ptr管理connection
销毁shared_ptr时,对connection调用end_connection: connection仍存在,可再次使用
1void end_connection(connection *p) { disconnect(*p); } 2 3void f(destination &d) 4{ 5 connection c = connect(&d); 6 shared_ptr<connection> p(&c, end_connection); // 销毁p时会对c调用end_connection 7}
shared_ptr接管动态对象时, 为动态对象绑定删除器
reset
提供重载版本: 第一个参数的缺省值为nullptr,第二个参数的缺省值为delete
-
形参列表为空: 将shared_ptr置空
如果需要销毁动态对象, 使用delete运算符 -
传入内置指针: 从内置指针接管动态对象
免去显式转换如果需要销毁动态对象, 使用delete运算符
-
传入内置指针和删除器: 从内置指针接管动态对象, 并为该动态对象绑定删除器
之后删除该动态对象时, 使用删除器联合管理同一动态对象的计数器和删除器(如有绑定)是共用的
1sp.reset(); 2// => 3// sp = nullptr; 4 5sp.reset(p); 6// => 7// sp = shared_ptr<T>(p); 8 9sp.reset(p, d);
示例
1#include <iostream> 2#include <string> 3#include <vector> 4#include <memory> 5 6using std::cout; 7using std::endl; 8using std::string; 9 10void DeleteString(string *ps) 11{ 12 if (ps) { 13 cout << "Delete " << *ps << endl << endl; 14 delete ps; 15 } 16} 17 18void DeleteString1(string *ps) 19{ 20 cout << "This is " << __FUNCTION__ << ": "; 21 DeleteString(ps); 22} 23 24void DeleteString2(string *ps) 25{ 26 cout << "This is " << __FUNCTION__ << ": "; 27 DeleteString(ps); 28} 29 30int main(int argc, const char * argv[]) 31{ 32 auto p = new string("Hat"); 33 auto p2 = new string("Shoe"); 34 std::shared_ptr<string> sp(p, DeleteString1); // 为Hat绑定删除器DeleteString1 35 sp.reset(p2, DeleteString2); // 为Hat调用删除器DeleteString1; 为Shoe绑定删除器DeleteString2 36 37 auto sp2 = sp; 38 sp = nullptr; 39 cout << "main finished.\n\n"; 40 return 0; 41} // 为Shoe调用删除器DeleteString2
输出
This is DeleteString1: Delete Hat main finished. This is DeleteString2: Delete Shoe
注意: 使用一个shared_ptr初始化另一个shared_ptr时, 传入删除器
P413提到了该操作
1shared_ptr<T> sp1(sp2, d);
想要探究sp2所指动态对象的销毁途径, 但无法正确执行该操作. 做了以下尝试, 皆不成:
-
只sp2拥有删除器
1auto p = new Foo("Peter"); 2shared_ptr<Foo> sp1(p); 3 4shared_ptr<Foo> sp2(sp1, DeleteFoo); // 报错: no known conversion from 'shared_ptr<Foo>' to 'std::nullptr_t' 5 6// 仅说明意图 7sp2 = nullptr;
-
sp1和sp2拥有相同的删除器
1auto p = new Foo("Peter"); 2shared_ptr<Foo> sp1(p, DeleteFoo); // 为Peter绑定删除器 3 4shared_ptr<Foo> sp2(sp1, DeleteFoo); // 报错: no known conversion from 'shared_ptr<Foo>' to 'std::nullptr_t'
-
sp2为移后源
1auto p = new Foo("Peter"); 2shared_ptr<Foo> sp1(p); 3 4shared_ptr<Foo> sp2(std::move(sp1), DeleteFoo); // 报错: no known conversion from 'typename remove_reference<shared_ptr<Foo> &>::type' (aka 'std::shared_ptr<Foo>') to 'std::nullptr_t'