C++ 智能指针
智能指针
是一个具体的类,生成智能指针对象时,在栈上,根据栈上对象出作用域自动析构的特点,达到对资源的释放 。
智能指针的浅拷贝问题 :
不带引用计数
- c++库 : auto_ptr(c++11 废弃)
- c11 新标准
- scopet_ptr
- unique_ptr
auto_ptr:
auto_ptr<int> ptr1 (new int); auto_ptr<int> ptr2(ptr1);
auto_ptr 处理浅拷贝逻辑 源码上调用了 ptr1.release() 将ptr1 指向的空间 交给ptr2,将ptr1置为nullptr。
也就是说 将内存的控制权交给最后一个auto_ptr指针,那么在释放ptr1 会出错,这种情况对于不了解实现的用户是危险的
因此不推荐使用auto_ptr,因此在容器vector 或者其他容器中不能使用auto_ptr,只能在情况特别简单的情况下
scopet_ptr 的做法:
scopet_ptr(const scopet_ptr<T>&) = delete; scopet_ptr<T> & operator= (const scopet_ptr<T> &) = delete;
直接将拷贝构造函数,赋值构造函数删除,无法进行赋值操作
推荐使用unique_ptr 做法:
unique_ptr(const unique_ptr<T>&) = delete; unique_ptr<T> & operator= (const unique_ptr<T> &) = delete; 提供 unique_ptr(unique_ptr<T> && src) unique_ptr<T> & operator = (unique_ptr<T> &&src)
那么我们在使用的时候 可以这样
unique_ptr<int> p1 (new int); unique_ptr<int> p2(std::move(p1))
unique_ptr 提供了右值拷贝构造和赋值函数,那么我们使用c++11的std::move 获取右值,用户很清楚自己的操作,不会向auto_ptr一样。
带引用计数的智能指针:
shared_ptr 和 weak_ptr (多个智能指针可以管理一个资源)
对每一个对象资源匹配一个引用计数,当出作用域的时候,当引用计数不为0 的时候,不析构。
实现shared_ptr
#include<iostream> #include<stdlib.h> #include<string.h> #include<string> #include<unistd.h> #include<atomic> using namespace std; template<typename T> class RefCnt { public: RefCnt(T * ptr = nullptr):mptr(ptr) { if(mptr != nullptr ) { mcount = 1; } } void addMcount() {mcount++;} int delMcount() { return --mcount;} private: atomic_int mcount; T * mptr; }; template<typename T> class Myshared_ptr{ public: Myshared_ptr(T * ptr =nullptr ) :mptr(ptr) { if(mptr != nullptr) { mRefCnt = new RefCnt<T>(mptr); } } ~Myshared_ptr() { if(0 == mRefCnt->delMcount()) { delete mptr; mptr == nullptr; } } T & operator *() {return *mptr;} T & operator ->() {return mptr;} Myshared_ptr (const Myshared_ptr<T> & src):mptr(src.mptr),mRefCnt(src.mRefCnt) { if(mptr != nullptr) { mRefCnt->addMcount(); } } Myshared_ptr<T> & operator= (const Myshared_ptr<T> &src) { if(this == &src) { return *this; } if(0 == mRefCnt->delMcount()){ delete mptr; } mptr = src.mptr; mRefCnt = src.mRefCnt; return *this; } private: RefCnt<T> * mRefCnt; T * mptr; }; int main() { Myshared_ptr<int> p(new int); Myshared_ptr<int> p2(new int); p2 = p; cout<<endl; return 0; }
那么当多个指针管理同一个资源的时候,只是对引用计数的更改,当引用计数为0 的时候,析构资源。
shared_ptr 的交叉引用问题
shared_ptr(强智能指针) weak_ptr(若智能指针)可以理解为:强智能指针管理内存,弱智能指针观察强智能指针
#include<iostream> #include<stdlib.h> #include<string.h> #include<string> #include<unistd.h> #include<memory> using namespace std; class B; class A { public: A(){ cout<<"A()"<<endl; } ~A(){ cout<<"~A()"<<endl; } shared_ptr<B> _ptrb; }; class B { public: B() {cout<<"B()"<<endl;} ~B() {cout<<"~B()"<<endl;} shared_ptr<A> _ptra; }; int main() { shared_ptr<A> ptra(new A); shared_ptr<B> ptrb(new B); ptra->_ptrb = ptrb; ptrb->_ptra = ptra; cout<<endl; return 0; }
这样的操作会让引用计数为2 无法释放,因此需要使用wead_ptr ,不会对引用计数更改,结论:定义对象的时候用强智能指针,对象引用的时候用弱指针指针
| 操作 | 功能描述 |
|---|---|
| weak_ptr<T> w | 空weak_ptr,可以指向类型为T*的对象。 |
| weak_ptr<T> w(sp) | 与shared_sp sp指向相同对象的weak_ptr。T必须能转换为sp所指的类型。 |
| w = p | p可以是一个shared_ptr或一个weak_ptr。赋值后w指向p所指的对象。 |
| w.reset() | 将w置为空 |
| w.use_count() | 与w共享对象的shared_ptr的数量 |
| w.expired() | 若w.use_count()为0,返回true,否则返回false |
| w.lock() | 如果expired()为true,返回一个空shared_ptr;否则返回一个指向w所指对象的shared_ptr。 |
特点 weak_ptr 没有* 和-> 运算符重载,需要使用w.lock() 挺升能力。
在多线程中 提升完判断 是否为空,来判断资源是否还在。

浙公网安备 33010602011771号