【C++】智能指针

来源:互联网 发布:淘宝卖家要在哪看粉丝 编辑:程序博客网 时间:2024/06/18 10:23

    在C++中,我们经常会用到动态开辟内存,需要我们自己维护,在出函数作用域之前,必须将管理的内存释放掉,否则就会造成内存泄漏,即使我们十分小心,但总有可能出错,因此便有了智能指针。

RAII:资源分配即初始化:定义一个类来封装资源的分配和释放,在构造函数完成资源的分配和初始化,在析构函数完成资源的清理,可以保证资源的正确初始化和释放。

1. auto_ptr,auto_ptr的实现机制是资源的转移,在拷贝构造函数和运算符重载函数中将当前对象的指针置为空,以实现资源的转移

template <class T>class AutoPtr{public:AutoPtr(T* ptr = NULL): _ptr(ptr){}~AutoPtr(){if (_ptr){delete _ptr;_ptr = NULL;}}T& operator*(){return (*_ptr);}T* operator->(){return _ptr;}AutoPtr(AutoPtr& ap): _ptr(ap._ptr){ap._ptr = NULL;}AutoPtr& operator=(AutoPtr& ap){if (this != &ap){if (_ptr)delete _ptr;_ptr = ap._ptr;ap._ptr = NULL;}return *this;}private:T* _ptr;};
它的缺陷是:当我们用一个对象去构造另一个对象时,原对象由于被置为NULL,则不能再使用了。

我们可以设置增加一个变量,当前对象如果为该资源的拥有者,则可以释放空间,否则,它将只有使用权。

template <class T>class AutoPtr{public:AutoPtr(T* ptr = NULL): _ptr(ptr), _owner(true){if (NULL == _ptr)_owner = false;}AutoPtr(const AutoPtr& ap): _ptr(ap._ptr), _owner(ap._owner){ap._owner = false;}AutoPtr& operator=(const AutoPtr& ap){if (this != &ap){if (_ptr)delete _ptr;_ptr = ap._ptr;_owner = ap._owner;ap._owner = false;}return *this;}~AutoPtr(){if (_ptr && _owner == true){delete _ptr;_owner = false;_ptr = NULL;}}private:T* _ptr;mutable bool _owner;};
它的缺陷是:如果我们在一个if的作用域中用对象ap1创建了ap2,那出了作用域,ap2被释放,ap1中的_ptr变成了野指针,无法再使用。因此,C++11建议不要使用auto_ptr。

2. scoped_ptr,这是boost库中的智能指针,它的实现机制是防拷贝,将拷贝构造函数和赋值运算符重载只声明而不定义,并设为私有成员。在C++标准库中unique_ptr与它的实现机制类似。

template<class T>class ScopedPtr{public:ScopedPtr(T* ptr = NULL): _ptr(ptr){}~ScopedPtr(){if (_ptr){delete _ptr;_ptr = NULL;}}T* operator->(){return _ptr;}T& operator*(){return *_ptr;}private://防拷贝,将声明设为私有而不定义ScopedPtr(const ScopedPtr& sp);ScopedPtr& operator=(const ScopedPtr sp);private:T* _ptr;};
3. shared_ptr,它的实现原理类似于string类中的引用计数。拷贝一次,引用计数增加1,当引用计数为0时2,释放空间。

template<class T>class SharedPtr{public:SharedPtr(T* ptr = NULL): _ptr(ptr), _pCount(new int(0)){if (_ptr)*_pCount = 1;}SharedPtr(const SharedPtr& sp): _ptr(sp._ptr), _pCount(sp._pCount){(*_pCount)++;}SharedPtr& operator=(const SharedPtr& sp){if (this != &sp){if (_pCount && --(*_pCount) == 0){delete _ptr;delete _pCount;}_ptr = sp._ptr;_pCount = sp._pCount;if (*_pCount)(*_pCount)++;}return *this;}~SharedPtr(){if (_ptr && --(*_pCount)){delete _ptr;_ptr = NULL;          delete _pCount;          _pConut=NULL;}}T* operator->(){return _ptr;}T& operator*(){return *_ptr;}private:T* _ptr;int* _pCount;};
weak_ptr与shared_ptr搭配使用,shared_ptr中存在着循环引用的问题。例如:

template<class T>struct Node{Node(const T& data): _data(data){cout << "Node()" << this << endl;}T _data;weak_ptr<Node<T>> _pNext;weak_ptr<Node<T>> _pPre;~Node(){cout << "~Node()" << this << endl;}};int main(){shared_ptr<Node<int>> sp1(new Node<int>(10));shared_ptr<Node<int>> sp2(new Node<int>(20));cout << sp1.use_count() << endl;cout << sp2.use_count() << endl;sp1->_pNext = sp2;sp2->_pPre = sp1;cout << sp1.use_count() << endl;cout << sp2.use_count() << endl;return 0;}
如果只是shared_ptr,由于sp1的next指向了sp2,sp2的pre指向了sp1,因此sp1和sp2的count为2,无法完成析构。当使用了weak_ptr时,引用计数count没有增加,增加的是weak计数。


原创粉丝点击