智能指针

一、什么是智能指针

  智能指针是一个类,这个类的构造函数中传入一个指针,析构函数中释放传入的指针。智能指针都是栈上那个的对象,所以当函数(或程序)结束时都会被自动释放。

二、为什么要使用智能指针

    我们知道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;
}

小结:

  1. 创建对象的时候用shared_ptr强智能指针,别的地方一律持有weak_ptr弱类型指针,否则析构顺序会出现错误。
  2. 当通过弱智能指针访问对象时,需要先进行lock提升操作,提升成功,证明对象还在,再通过强智能指针访问对象。

版权声明:本文为YL970302原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。