一、什么是智能指针
智能指针是一个类,这个类的构造函数中传入一个指针,析构函数中释放传入的指针。智能指针都是栈上那个的对象,所以当函数(或程序)结束时都会被自动释放。
二、为什么要使用智能指针
我们知道C++的内存管理是让人很头疼的事,当我们写一个new语句时,一般就会立即把delete语句也直接写了,但是我们不能避免程序还未执行到delete时就跳转了,或者在函数中没有执行到最后的delete语句就返回了,如果我们不在每一个可能跳转或者返回的语句前释放资源,就会造成内存泄漏。使用智能指针可以在很大程度上避免这个问题,因为智能指针就是一个类,当超出了类的作用域时,类会自动调用析构函数,析构函数会自动释放资源
三、常见的智能指针
(1)shared_ptr(强智能指针):从名字share就可以看出了资源可以被多个指针共享,它使用计数机制来表明资源被几个指针共享。可以通过成员函数use_count()来查看资源的所有者个数。出了可以通过new来构造,还可以通过传入auto_ptr, unique_ptr,weak_ptr来构造。当我们调用release()时,当前指针会释放资源所有权,计数减一。当计数等于0时,资源会被释放。具体的成员函数解释可以参考
template<typename T>
class smartPtr
{
private:
T *_ptr;
static map<T*, int> _num;//指针----引用计数
public:
smartPtr(T *p)
{
_ptr = p;
//先找
if (_num.find(p) != _num.end())
{
_num[p]++;
}
else
{
_num.insert(make_pair(p, 1));
}
cout << _ptr << ':' << _num[_ptr] << endl;
}
smartPtr(const smartPtr& src)
{
_ptr = src._ptr ;
_num[src._ptr]++;
}
~smartPtr()
{
cout << "~smartPtr()" << endl;
if (--_num[_ptr] == 0)
{
delete _ptr;
}
cout << _ptr << ':' << _num[_ptr] << endl;
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
};
template<typename T>
map<T*, int> smartPtr<T>::_num =map<T*, int>();(2)weak_ptr(弱智能指针):weak_ptr是用来解决shared_ptr相互引用时的死锁问题,如果说两个shared_ptr相互引用,那么这两个指针的引用计数永远不可能下降为0,资源永远不会释放。它是对对象的一种弱引用,不会增加对象的引用计数,和shared_ptr之间可以相互转化,shared_ptr可以直接赋值给它,它可以通过调用lock函数来获得shared_ptr
交叉引用代码
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;
return 0;
}
显然,A类中有一个指向B类的shared_ptr强类型智能指针,B类中有一个指向A的shared_ptr强类型智能指针。此时,有两个强智能指针指向了对象A,对象A的引用计数为2.也有两个强智能指针指向了对象B,对象B的引用计数也为2。当主函数返回后,对象A和B的引用计数都减为1,此时因为引用计数不为0,并没有释放内存,程序结束造成内存泄漏。
所以解决的办法就是:将A类和B类中的shared_ptr强智能指针都换成weak_ptr弱智能指针。在使用强弱智能指针的时候,有一个规定,就是创建对象的时候,持有它的强智能指针,当其他地方想使用这个对象的时候,应该持有该对象的弱智能指针
利用weak_ptr解决交叉引用代码
class B;
class A
{
public:
A()
{
cout << "A()" <<endl;
}
~A()
{
cout << "~A()" <<endl;
}
weak_ptr<B> _ptrb;//其他地方持有对象的弱智能指针
};
class B
{
public:
B()
{
cout << "B()" <<endl;
}
~B()
{
cout << "~B()" <<endl;
}
weak_ptr<A> _ptra;//其他地方持有对象的弱智能指针
};
int main()
{
shared_ptr<A> ptra(new A());//创建对象的时候持有强智能指针
shared_ptr<B> ptrb(new B());//创建对象的时候持有强智能指针
ptra->ptrb = ptrb;
ptrb->ptra = ptra;
return 0;
}
小结:
- 创建对象的时候用shared_ptr强智能指针,别的地方一律持有weak_ptr弱类型指针,否则析构顺序会出现错误。
- 当通过弱智能指针访问对象时,需要先进行lock提升操作,提升成功,证明对象还在,再通过强智能指针访问对象。