C++ Insight: 自动指针 auto_ptr
C/C++ 程序开发里的指针管理——主要时指针释放——很容易出错。
比如下面的例子如果忘记在函数返回之前释放指针,会造成内存泄漏。
void foobar(){
Car *mycar = new Car();
...
delete mycar; // Q: The problem
return;
}
用 auto_ptr 自动释放指针
利用 C++ 里类对象(不是指针)会自动销毁(调用 destructor )可以提出如下方案。
void foobar_autoptr(){
auto_ptr<Car> mycar_auto = new Car(); // A: a solution
...
// delete mycar; //-- not needed
//-- mycar destructor will handle it
return;
}
auto_ptr 的实现
根据上面的需求,利用模板,很容易得出如下解决方案。
template<class T> class auto_ptr {
public:
T *vp;
auto_ptr(T *p):vp(p){}
~auto_ptr(){
if( vp!=NULL ) delete vp;
}
operator = (T *target) {
vp = target;
}
}
避免重复释放 Double-Free
关于指针的另一个容易出问题的情况是重复释放。实质就是
delete p; // 第一次释放,假设没问题。
delete p; // 这里会出问题
导致这种情况发生的情形包括函数参数传递
void foobar_autoptr(){
auto_ptr<Car> mycar_auto = new Car();
bar(mycar); // 参数传递,
// 此时指针已经在 bar() 调用结束前被释放
// 当前函数返回前,指针会被再次释放,就要出问题了
return;
}
转移控制权
解决办法之一是永远保持所有权的唯一性。因此需要重载 Copy Constructor 和 复制运算符。
template<class T> class auto_ptr {
auto_ptr(auto_ptr &from){
vp = from.vp;
from.vp = NULL;
}
operator = (auto_ptr &from) {
vp = from.vp;
from.vp = NULL;
}
}
接口
template<class T> class auto_ptr {
T& operator *(){
return *vp;
}
T* operator ->(){
return vp;
}
T* get() const {return vp;}
T* release() {
T* result = vp;
vp = NULL;
return result;
}
void reset(T* p = 0) {
if(vp!=NULL) delete vp;
vp = p;
}
}