- 智能指针实质是一个对象,行为表现的像指针
- RAII(资源获取即初始化)对普通指针进行封装
- 值语义转换成引用语义
- 避免出错跳转catch导致try中的delete没有运行
智能指针的使用
shared_ptr使用
shared_ptr多个指针指向相同的对象。shared_ptr使用引用计数,每一个shared_ptr的拷贝都指向相同的内存。每使用他一次,内部的引用计数加1,每析构一次,内部的引用计数减1,减为0时,自动删除所指向的堆内存。shared_ptr内部的引用计数是线程安全的,但是对象的读取需要加锁。
- 初始化:构造函数或make_shared
- 拷贝和赋值
- 拷贝使引用+1;
- 赋值使得原对象引用-1;
- get获得原始指针
- 注意不要用一个原始指针初始化多个shared_ptr,会造成double free
- 注意避免循环引用,shared_ptr的一个最大的陷阱是循环引用,循环,循环引用会导致堆内存无法正确释放,导致内存泄漏。
循环引用
```cpp class B; // 前置声明 class A { public: shared_ptr ptr; };
class B { public: shared_ptr ptr; };
int main() { while(true) { shared_ptr pa(new A()); shared_ptr pb(new B()); pa -> ptr = pb; pb -> ptr = pa; } return 0; }
<a name="sDSbQ"></a>## 上图中,class A和class B的对象各自被两个智能指针管理,也就是A object和B object引用计数都为2,为什么是2?分析class A对象的引用情况,该对象被main函数中的pa和class B对象中的ptr管理,因此A object引用计数是2,B object同理。在这种情况下,在main函数中一个while循环结束的时候,pa和pb的析构函数被调用,但是class A对象和class B对象仍然被一个智能指针管理,A object和B object引用计数变成1,于是这两个对象的内存无法被释放,造成内存泄漏,如下图所示<br /><a name="XeWoV"></a>## unique_ptr使用同一时刻只能有一个unique_ptr指向给定对象(通过禁止**拷贝语义,**只有**移动语义**来实现)。- 生命周期:unique_ptr指针创建时开始,直到离开作用域- 对象销毁(默认使用delete操作符,用户可指定其他操作)- 智能指针所指对象改变:构造函数,reset方法重新指定,release,移动语义<a name="fAbWk"></a>## weak_ptr(资源观测权)的使用为配合shared_ptr的使用,不具备普通指针的行为,没有重载`operator*和->`,它的最大作用在于协助shared_ptr工作,像旁观者那样观测资源的使用情况。- 可从shared_ptr或者weak_ptr对象构造,获得资源观测权- 构造不会引起指针引用计数增加- use_count():引用计数;expired(),不复存在- lock():从被观测的shared_ptr中获取shared_ptr对象,但当expired()==true时,lock()函数将返回一个存储空指针的shared_ptr<a name="S5NGe"></a>## 实现原理> 智能指针将一个**计数器与类指向的对象**相关联,引用计数跟踪该类有多少个对象共享同一指针- 每次创建类的对象时,初始化指针并将引用计数置1;- 拷贝构造函数:拷贝指针并增加对应的引用计数。- 赋值拷贝:减少左操作数的引用计数并增加右操作数- 析构函数: 减少引用计数- 重载`->`和`*`- 自动销毁:栈对象的有限作用域以及临时对象(**有限作用域**实现)析构函数释放内存```cpptemplate<typename T>class SmartPointer{private:T* _ptr;size_t* _count;public:SmartPointer(T* ptr==nullptr):_ptr(ptr){if(_ptr){_count=new size_t(1);}else{_count=new size_t(0);}}SmartPointer(const SmartPointer& _sp){if(this!=&_sp){this->_ptr=_sp._ptr;*this->_count=_sp._count;(*this->_count)++;}}SmartPointer& operator=(const SmartPointer& _sp){if(this!=&sp){if(this->_ptr){(*this->_count)--;if((*this->_count)==0){delete this->_count;delete this->_ptr;}}this->_ptr=_sp._ptr;this->_count=_sp._count;(*this->_count)++;return *this;}}T& operator*() const{assert(this->_ptr!=nullptr);return *(this->_ptr);}T* operator->() const {assert(this->_ptr!=nullptr);return this->_ptr;}T* get() const {return this->_ptr;}~SmartPointer(){(*this->_count)--;if((*this->_count)==0){delete this->_count;delete this->_ptr;}}size_t use_count() const{return *(this->_count);}bool expired() const {return use_count()==0;}}
