本文将分析一下c++中自带的auto_ptr在使用中需要注意的一个问题。首先看一段代码:
// auto_ptr example
#include <iostream>
#include <memory>
using namespace std;
int main ()
{
auto_ptr<int> p1 (new int);
*p1.get()=10;
{
auto_ptr<int> p2 (p1);
cout << "p2 points to " << *p2 << "\n";
}
cout << "p1 points to " << *p1 << "\n";
return 0;
}
猜测一下这段程序的输出?如果不出意外,得到的结果应该是如下这样的。
p2 points to 10
Segmentation fault (core dumped)
你可能会奇怪,为什么对p1的引用会出现段错误了呢?好吧,我们来看一下auto_ptr的源代码。
namespace std {
// auxiliary type to enable copies and assignments (now global)
template<class Y>
struct auto_ptr_ref {
Y* yp;
auto_ptr_ref (Y* rhs)
: yp(rhs) {
}
};
template<class T>
class auto_ptr
{
private:
T* ap; // refers to the actual owned object (if any)
public:
typedef T element_type;
// constructor
explicit auto_ptr (T* ptr = 0) throw() : ap(ptr) { }
// copy constructors (with implicit conversion)
// - note: nonconstant parameter
auto_ptr (auto_ptr& rhs) throw() : ap(rhs.release()) { }
template<class Y>
auto_ptr (auto_ptr<Y>& rhs) throw() : ap(rhs.release()) { }
// assignments (with implicit conversion)
// - note: nonconstant parameter
auto_ptr& operator= (auto_ptr& rhs) throw()
{
reset(rhs.release());
return *this;
}
template<class Y>
auto_ptr& operator= (auto_ptr<Y>& rhs) throw()
{
reset(rhs.release());
return *this;
}
// destructor, 注意这里释放内存。。
~auto_ptr() throw()
{
delete ap;
}
// value access
T* get() const throw()
{
return ap;
}
T& operator*() const throw()
{
return *ap;
}
T* operator->() const throw()
{
return ap;
}
// release ownership
T* release() throw()
{
T* tmp(ap);
ap = 0;
return tmp;
}
// reset value
void reset (T* ptr=0) throw()
{
if (ap != ptr)
{
delete ap;
ap = ptr;
}
}
}
}
一般我们会认为智能指针都是采用一种引用计数的方式来管理已分配的内存,也就是说会在最后一个智能指针对象调用析构函数时将分配的内存释放掉,然而仔细看auto_ptr的源代码会发现,其实它的实现并没有采用引用计数的方式来实现,因为只要任何一个auto_ptr对象调用析构函数,内存就一定会被释放掉,这就是为何对p1的引用会出现段错误,因为p2在对p1引用之前已经将分配的内存给释放掉了。