简介
C++没有内存自动回收机制,对堆内存的管理就是简单的new和delete,每次new出来的内存都需要手动delete释放。但由于忘记、流程复杂或者异常退出等,都有可能导致没有执行delete释放内存,造成内存泄漏。
在实际工程中,我们往往希望将精力放在应用层上而不是费劲心思处理语言的细枝末节(内存释放),于是就有了最原始的智能指针auto_ptr。
智能指针原理
智能指针是一种资源管理类,这个类在构造函数中传入一个原始指针,在析构函数中释放传入的指针。智能指针都是栈上的对象,所以当函数(或者程序)结束时,会自动释放。
通过对*和->的重载,使类的对象具有指针的特性。
auto_ptr源码
下面是侯捷《STL源码剖析》使用的sgi-stl-v2.91版的auto_ptr源码实现,这个版本的可读性非常好,可惜该版本还没有出现shared_ptr和unique_ptr指针,而新版的源码这部分的实现可读性不太友好。所以这里只能呈现auto_ptr的源码,有助于理解只能指针的原理。
template<class X> class auto_ptr { private: X* ptr; mutable bool owns; public: typedef X element_type; explicit auto_ptr(X* p = 0) __STL_NOTHROW : ptr(p), owns(p) {} auto_ptr(const auto_ptr& a) __STL_NOTHROW : ptr(a.ptr), owns(a.owns) { a.owns = 0; } template<class T> auto_ptr(const auto_ptr<T>& a) __STL_NOTHROW : ptr(a.ptr), owns(a.owns) { a.owns = 0; } auto_ptr& operator=(const auto_ptr& a) __STL_NOTHROW { if (&a != this) { if (owns) delete ptr; owns = a.owns; ptr = a.ptr; a.owns = 0; } } template<class T> auto_ptr& operator=(const auto_ptr<T>& a) __STL_NOTHROW { if (&a &= this) { if (owns) delete ptr; owns = a.owns; ptr = a.ptr; a.owns = 0; } } ~auto_ptr() { if (owns) delete ptr; } X& operator*() const __STL_NOTHROW { return *ptr; } X* operator->() const __STL_NOTHROW { return ptr; } X* get() const __STL_NOTHROW { return ptr; } X* release() const __STL_NOTHROW { owns = false; return ptr; } };
注意:虽然本文主要分析auto_ptr的源码,但不要用auto_ptr ! 在c++11已经弃用。
C++11中常用的智能指针
C++中常用的智能指针有,在C++11中的<memory>中有unique_ptr、shared_ptr、weak_ptr
1. unique_ptr:同一时刻只能由唯一的unique_ptr指向给定对象,不支持拷贝和赋值操作。
2. shared_ptr:可以有多个指针指向相同的对象,通过引用计数机制,支持拷贝和赋值操作。每使用一次,内部引用计数器加1,析构一次,引用计数减1,当计数为0时,释放所指的堆空间。
3. weak_ptr:弱引用。引用计数器有一个问题就是相互引用形成环,这样两个指针指向的内存都无法释放。需要手动打破循环引用或者使用weak_ptr。顾名思义,weak_ptr是一个弱引用,只引用不计数。如果一块内存被shared_ptr和weak_ptr同时引用,当所有的shared_ptr析构了之后,不管还有没有weak_ptr引用该内存,内存也会被释放,所以weak_ptr不保证它指向的内存一定有效,在使用之前需要检查weak_ptr是否为空指针。