在智能指针中shared_ptr用来计算指向对象的指针的个数,但是如果先执行shared_ptr1=shared_ptr2,再执行shared_ptr2=shared_ptr1,这样shared_ptr1.count()和shared_ptr2.count()都为1,这就造成了循环引用,循环引用会导致堆内存无法正确释放,导致内存泄露。
考虑一个简单的对象——家长与子女:a Parent has a Child,a Child Knows his parent。在C++中,如果使用原始指针作为成员,Child和Parent由谁释放?如何保证指针的有效性?如何防止出现悬空指针?这里就需要利用智能指针去实现,智能指针可以将对象语义转变为值语义,shared_ptr能轻松的解决生命周期的问题,不必担心悬空指针。但是这个模型存在循环引用的问题,就需要利用weak_ptr。
原始指针的做法(容易出错):
#include<bits/stdc++.h> using namespace std; class Parent; class Child; class Parent{ private: Child* myChild; public: void setChild(Child* ch){ this->myChild=ch; } void dosomething(){ if(this->myChild){ cout<<"Parent"<<endl; } } ~Parent(){ delete myChild; } }; class Child{ private: Parent* myParent; public: void setParent(Parent* p){ this->myParent=p; } void dosomething(){ if(this->myParent){ cout<<"Child"<<endl; } } ~Child(){ delete myParent; } }; int main(){ { Parent *p=new Parent; Child *c=new Child; p->setChild(c); c->setParent(p); p->dosomething(); //Parent c->dosomething(); //Child delete c; //仅删除这一个 // p->dosomething(); 不能访问 } return 0; }
循环引用内存泄露的写法:
#include<bits/stdc++.h> using namespace std; class Parent; class Child; class Parent{ private: shared_ptr<Child> myChild; public: void setChild(shared_ptr<Child> ch){ this->myChild=ch; } void dosomething(){ if(this->myChild.use_count()){ cout<<"Parent"<<endl; } } ~Parent(){ } }; class Child{ private: shared_ptr<Parent> myParent; public: void setParent(shared_ptr<Parent> p){ this->myParent=p; } void dosomething(){ if(this->myParent.use_count()){ cout<<"Child"<<endl; } } ~Child(){ } }; int main(){ weak_ptr<Parent> wpp; weak_ptr<Child> wpc; { shared_ptr<Parent> p(new Parent); shared_ptr<Child> c(new Child); p->setChild(c); cout<<p.use_count()<<endl;//1 cout<<c.use_count()<<endl;//2 c->setParent(p); cout<<p.use_count()<<endl;//2 cout<<c.use_count()<<endl;//2 wpp=p; wpc=c; } //超出该域,p、c都已被析构,但是weak_ptr显示p、c的引用都为1 cout<<wpp.use_count()<<endl;//1 cout<<wpc.use_count()<<endl;//1 return 0; }
正确做法是:
#include<bits/stdc++.h> using namespace std; class Parent; class Child; class Parent{ private: weak_ptr<Child> myChild; public: void setChild(shared_ptr<Child> ch){ this->myChild=ch; } void dosomething(){ if(this->myChild.lock()){ cout<<"Parent"<<endl; } } ~Parent(){ } }; class Child{ private: shared_ptr<Parent> myParent; public: void setParent(shared_ptr<Parent> p){ this->myParent=p; } void dosomething(){ if(this->myParent.use_count()){ cout<<"Child"<<endl; } } ~Child(){ } }; int main(){ weak_ptr<Parent> wpp; weak_ptr<Child> wpc; { shared_ptr<Parent> p(new Parent); shared_ptr<Child> c(new Child); p->setChild(c); cout<<p.use_count()<<endl;//1 cout<<c.use_count()<<endl;//1 c->setParent(p); cout<<p.use_count()<<endl;//2 cout<<c.use_count()<<endl;//1 wpp=p; wpc=c; } cout<<wpp.use_count()<<endl;//0 cout<<wpc.use_count()<<endl;//0 return 0; }
下面是一个简单智能指针的demo。智能指针类将一个计数器与类指向的对象相关联,引用计数跟踪该类有多少个对象共享同一指针。每次创建类的新对象时,初始化指针并将引用计数置为1;当对象作为另一对象的副本而创建时,拷贝构造函数拷贝指针并增加与之相应的引用计数;对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数(如果引用计数为减至0,则删除对象),并增加右操作数所指对象的引用计数;调用析构函数时,构造函数减少引用计数(如果引用计数减至0,则删除基础对象)。智能指针就是模拟指针动作的类。所有的智能指针都会重载 -> 和 * 操作符。智能指针还有许多其他功能,比较有用的是自动销毁。这主要是利用栈对象的有限作用域以及临时对象(有限作用域实现)析构函数释放内存。
#include<bits/stdc++.h> using namespace std; template<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& ptr){//拷贝构造函数 if(this !=&ptr){ this->_ptr=ptr._ptr; this->_count=ptr._count; (*this->_count)++; } } smartPointer& operator =(const smartPointer& ptr){//赋值构造函数 if (this->_ptr == ptr._ptr) { return *this; } if(this->_ptr){ (*this->_count)--; if(*this->_count==0){ delete this->_ptr; delete this->_count; } } this->_ptr=ptr._ptr; this->_count=ptr._count; (*this->_count)++; return *this; } T& operator *(){//重载操作符 assert(this->_ptr==nullptr); return this->_ptr; } T& operator->(){//重载操作符 assert(this->_ptr==nullptr); return this->_ptr; } ~smartPointer(){//析构函数 (*this->_count)--; if(*this->_count==0){ delete this->_ptr; delete this->_count; } } size_t use_count(){ return *this->_count; } }; int main() { { smartPointer<int> sp(new int(10)); smartPointer<int> sp2(sp); smartPointer<int> sp3(new int(20)); sp=sp3; cout<<sp.use_count()<<endl;//1 cout<<sp2.use_count()<<endl;//2 cout<<sp3.use_count()<<endl;//2 } { shared_ptr<int> sp(new int(10)); shared_ptr<int> sp2(sp); shared_ptr<int> sp3(new int(20)); sp=sp3; cout<<sp.use_count()<<endl;//1 cout<<sp2.use_count()<<endl;//2 cout<<sp3.use_count()<<endl;//2 } return 0; }
参考地址:https://www.cnblogs.com/wxquare/p/4759020.html、《C++ primer》
原文地址:https://www.cnblogs.com/ybf-yyj/p/9661988.html