文章目录智能指针介绍无手写智能指针参考计数升级智能指针手写智能指针循环参考问题强智能指针弱智能指针弱智能指针升级为强智能指针共享对象
智能指针介绍
智能指针是一个类,它包含指向动态分配的“堆”对象的指针。 他们的工作原理类似于c的内置指针,除了可以在适当的时间自动删除指示的对象。 在遇到异常时,智能指针特别有用,因为它可以正确销毁动态分配的对象。 它还可以用于跟踪由多个用户共享的动态分配对象。
事实上,智能指针有很多,包括处理线程安全、在写入时提供复制、确保协议和提供远程交互服务。 有一种为这些extremelysmartpointers (esp )创建常规智能指针的方法,但它没有被复盖。
智能指针的使用大部分用于生存期控制、阶段控制。 它们使用operator-和operator*生成原始指针,使智能指针看起来像普通指针。
手写的智能指针请先举例来看。 否则,面对空气我也很尴尬。
# includeiostreamusingnamespacestd; templateclasstclasssmart _ ptr { public : smart _ ptr (t * ptr=null ptr ) {mptr=ptr; (}~smart_ptr ) ) {delete mptr; }private:T* mptr; (; int main () {/*int* p=new int; delete p; 应该是这样写的吧*/smart_ptrintsp(newint ); //现在这样写就好了return 0; }在此堆栈上构建的对象在退出范围时将自动解析,并释放指针。
既然我们现在把这样的对象作为新的指针对象,就有这么一句经典的话。 “裸体指针可以管理。必须由我来管理。 不能管理裸体指针必须由我来管理! ”
所以这一类应该丰富起来。
templateclasstclasssmart _ ptr { public : smart _ ptr (t * ptr=null ptr ) {mptr=ptr; (}~smart_ptr ) ) {delete mptr; } t操作器* () return* ) this-mptr ); } t *操作器- () {return this-mptr; }private:T* mptr; (; int main () smart_ptrintsp ) newint ); //现在这样写就可以了*sp=20; cout *sp endl; 返回0; }没有引用计数的智能指针上的代码没有引用计数,这有什么问题呢?
int main () smart_ptrintsp ) newint ); //现在这样写就可以了smart_ptrintps(sp ); 返回0; }这样就崩溃了。 为什么呢? 因为离开作用域时,ps先分析了结构,释放了资源; 然后,轮到sp求解结构时,就没有资源求解结构。
解析语法后清空吗? 有用吗? 不。
~smart_ptr () {delete mptr; mptr=nullptr; }问题是,这是一个浅拷贝。
那你要去写深度拷贝吗? 有用。 把资源复制到另一个空间,解析结构时,你走你的,我的。 但是,这不是违背了我们最原始的初衷吗? 裸指针可以做也需要智能指针可以做,裸指针可以这样直接复制吗? 还是资源? 智能指针不行吗?
那怎么办?
将带有引用计数的智能指针升级到手写智能指针。 shared_ptr和weak_ptr允许多个智能指针管理相同的资源,并提供了将引用计数与每个对象资源相匹配的方法。
# includeiostreamusingnamespacestd; 对templateclass TTclass Refcnt {//资源进行引用计数的public : refcnt (TT * ptr=nullptr ) ) {mptr=ptr; if(mptr ) {mcount=1; }}void addRef () {mcount; }int delRef () return----mcount; }private:TT* mptr; int mcount; (; templateclasstclasssmart _ ptr { public : smart _ ptr (t * ptr=null ptr ) {mptr=ptr; mrefcnt=newRefcntt(mptr; (}~smart_ptr ) ) if(0==mrefcnt-delref ) ) {delete mptr; mptr=nullptr; }}T operator* () return * (this-mptr ); } t *操作器- () {return this-mptr; }smart_ptr(constsmart_p
tr<T>& ptr) {mptr = ptr.mptr;mRefCnt = ptr.mRefCnt;if (mptr != nullptr) {mRefCnt->addRef();}}smart_ptr<T>& operator=(smart_ptr<T> &ptr) {if (this == &ptr) {return *this;}//要走之前,要先判断一下自己原先的资源有没有人接管if (0 == mRefCnt->delRef()) {delete mptr;}mptr = ptr.mptr;mRefCnt = ptr->mRefCnt;mRefCnt->addRef();return *this;}private:T* mptr;//指向资源Refcnt<T>* mRefCnt;//指向引用计数};int main() {smart_ptr<int> sp(new int);//现在这样写就好了smart_ptr<int> ps(sp);return 0;} 智能指针的循环引用问题 强智能指针使用引用计数的指针有:shared_ptr 和 weak_ptr,一个称为强智能指针,一个称为若智能指针。
强智能指针可以改变资源的引用计数,弱智能指针不会。
我们前面写的那个就是简化版的强智能指针。
但是呢,强智能指针有个很严重的问题,叫做循环引用,或者说“交叉引用”,这么说会不会比较明显点。
#include<iostream>#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> pa(new A());shared_ptr<B> pb(new B());cout << pa.use_count() << endl;cout << pb.use_count() << endl;//到这之前都很正常//pa->_ptrb = pb;//pb->_ptra = pa;return 0;} AB11~B~A那我现在把那两行放出来运行呢?
int main() {shared_ptr<A> pa(new A());shared_ptr<B> pb(new B());//到这之前都很正常pa->_ptrb = pb;pb->_ptra = pa;cout << pa.use_count() << endl;cout << pb.use_count() << endl;return 0;} AB22智能指针没有被正确的析构掉,那还能叫智能指针吗?
弱智能指针从上面的实验我们得出一个结论:在使用对象的时候,使用强智能指针;在引用对象的时候,使用弱智能指针。
怎么得出的呢?总不能说强智能指针不好用了就用弱的吧,主要是弱智能指针不改变计数,但是其实就相当于是一个观察者,对对象其实没有权限的。
改一下上面的代码,把类中的强智能指针改成弱的。再运行就正常。
弱智能指针升级为强智能指针接下来是不是就要问这个问题嘞?
类B里面去调用类A里面的一个方法,看看行不行。
void testB() {_ptra->testA();}很显然,是不行的。因为弱智能指针只会观察强指针。
那要用的时候怎么办呢?升级:
void testB() {shared_ptr<A> ps = _ptra.lock();//就是内个锁if (ps != nullptr) {//看一下资源是否还在ps->testA();}} 多线程访问共享对象在muduo库中多次使用了强弱智能指针
看一下普通指针在线程中的表现:
void handler(A* q) {std::this_thread::sleep_for(std::chrono::seconds(2));q->testA();}int main() {A* p = new A();thread t1(handler, p);delete p;t1.join();return 0;}这里问题就出来了,我先定义了一个线程,然后让线程休眠两秒,不过在主线程之中将这个指针给回收了,但是依然是在子线程中调用了 testA 的方法!!!
A~AA中的方法再拿弱智能指针对比一下:
void handler(weak_ptr<A> q) {//在使用智能指针的时候,要侦测指针是否存活shared_ptr<A> sp = q.lock();if (sp != nullptr) {sp->testA();}else {cout << "A对象已被析构" << endl;}}int main() {//加个作用域,让智能指针出作用域就析构掉{shared_ptr<A> p(new A());thread t1(handler, weak_ptr<A>(p));std::this_thread::sleep_for(std::chrono::seconds(2));//可以试试这行屏蔽了再运行看看t1.detach();}}