智能指针
2023年12月28日 2023年12月29日
smart pointer
模板类: 创建智能指针时, 需提供所指对象的类型
提供机制管理动态对象, 在满足条件的情况下自动销毁其所管理的动态对象
智能指针 | |
---|---|
shared_ptr | 允许多个shared_ptr共同管理同一个动态对象 |
unique_ptr | 独占管理的动态对象 |
weak_ptr | 伴随指针; 弱引用; 可以通过weak_ptr访问share_ptr管理的动态对象, 较内置指针更安全 |
头文件
1#include <memory>
shared_ptr和unique_ptr的共同操作
创建智能指针
创建空指针
未指向任何动态对象
1shared_ptr<T> sp; 2unique_ptr<T> up;
-
示例
1shared_ptr<string> sp1; 2shared_ptr<list<int>> sp2; 3 4unique_ptr<double> up1; 5unique_ptr<string> up2;
使用内置指针初始化智能指针
内置指针到智能指针是显式转换
-
使用new运算符为智能指针申请动态内存
存在一次转换: 内置指针转换为智能指针
- new运算符返回指向动态对象的内置指针
- 内置指针到智能指针的转换构造函数是explicit的
1shared_ptr<T> sp(new T(args)); 2unique_ptr<T> up(new T(args));
-
内置指针到智能指针的转换构造函数是explicit的
1shared_ptr<T> sp = new T(args); // 错误 2unique_ptr<T> up = new T(args); // 错误
1shared_ptr<T> sp = shared_ptr<T>(new T(args)); // 正确 2unique_ptr<T> up = unique_ptr<T>(new T(args)); // 正确
-
示例: 使用new运算符返回的内置指针初始化智能指针
1shared_ptr<int> p1(new int(10)); 2shared_ptr<int> p2 = shared_ptr<int>(new int(20)); 3 4unique_ptr<int> p3(new int(42)); 5unique_ptr<string> p4(new string("Stegosaurus")); 6unique_ptr<int> p5 = unique_ptr<int>(new int(10));
- new运算符返回指向动态对象的内置指针
-
内置指针将动态对象托管给智能指针
托管后, 建议将内置指针置空
1auto p1 = new T(args); 2auto p2 = new T(args); 3auto p3 = new T(args); 4auto p4 = new T(args); 5 6shared_ptr<T> sp1(p1); 7unique_ptr<T> up1(p2); 8 9shared_ptr<T> sp2 = shared_ptr<T>(p3); 10unique_ptr<T> up2 = unique_ptr<T>(p4); 11 12p1 = p2 = p3 = p4 = nullptr;
解引用智能指针
*
要求智能指针非空
获取所指对象的引用
1*p;
-
示例
1shared_ptr<string> p1(new string); 2if (p1 && p1->empty()) 3 *pi = "hi"; 4 5// 首先是p1不为空,其次要求其指向一个空串
从内置指针接管动态对象
1auto p5 = new T(args); 2auto p6 = new T(args); 3 4sp1 = shared_ptr<T>(p5); 5up1 = unique_ptr<T>(p6); 6 7p5 = p6 = nullptr;
访问动态对象
-
p指向是否为空
-
获取对象的引用
不要解引用一个空指针 -
访问对象成员
1p; 2*p; 3p->mem;
示例
1shared_ptr<string> sp(new string); 2 3if (sp && sp->empty()) 4{ 5 *sp = "hi"; 6} 7cout << *sp << endl;
get成员函数: 获取指向动态对象的内置指针
返回一个内置指针,指向智能指针管理的动态对象
实为智能指针到内置指针的转换
1T *pt = p.get();
通过内置指针使用动态对象期间,需要保证动态对象不被销毁
-
将管理动态对象的唯一一个shared_ptr置空, 触发动态对象销毁
1shared_ptr<string> sp(new string("hello")); 2string *ps = sp.get(); 3cout << *ps << endl; 4sp = nullptr; // 动态对象被销毁 5string s = *ps; // 错误: 访问非法内存 6cout << s << endl;
-
管理动态对象的唯一一个shared_ptr在块结束时被销毁, 触发动态对象销毁
sp和sp2的计数器不共用; 二者均以为自己是管理动态对象的唯一一个shared_ptr1shared_ptr<string> sp(new string("hello")); 2string *p = sp.get(); 3cout << *p << endl; 4{ 5 shared_ptr<string> sp2(p); 6} // 动态对象被销毁 7string foo = *sp; // 错误: 访问非法内存 8cout << foo << endl;
通过内置指针访问动态对象时, 不能对该指针执行delete操作,更不能将动态对象交接给其他智能指针
swap操作
有非成员函数和成员函数两个版本
1swap(p1, p2); 2p1.swap(p2);