auto_ptr用来防止内存泄露,通过管理指针对空间的拥有权来进行动态管理内存。尤其是在拷贝和赋值的时候容易出现内存泄漏或者多次释放同一内存空间。
template <class _Tp1>
auto_ptr(auto_ptr<_Tp1> & __a) : _M_ptr(__a.release()) { }
element_type * release() {
element_type * tmp = _M_ptr;
_M_ptr = 0;
return tmp;
}
auto_ptr<int> p1;
auto_ptr<int> p2(p1);
p1通过调用release成员函数,将p1的值拷贝给p2,然后p1指向空,结束p1对空间的使用权。也就是说不能再用p1去访问原来的空间,这样做在调用析构函数释放内存时,不会多次释放,因为拷贝或者是赋值,始终只有一个指针指向该空间。拷贝构造的参数为非常量的引用,因为需要改变当前对象_M_ptr的拥有权。
auto_ptr & operator=(const auto_ptr & __a) {
if (this != &__a) {
reset(__a.release());
}
}
void reset(element_type * __p = 0) {
if (__p != _M_ptr) {
delete _M_ptr;
_M_ptr = __p;
}
}
auto_ptr<int> p1;
auto_ptr<int> p2;
p2 = p1
在赋值的时候,如果p2指向了一个空间,结束p1的拥有权的时候,返回tmp,然后p2调用reset成员函数,判断p2与tmp指向的是否是同一空间,若不是,释放p2所指向的空间,将p2指向tmp指向的空间,完成赋值操作。
有如下拷贝初始化,但编译会出现错误。
auto_ptr<int> p1 = auto_ptr<int>(new int(10));
auto_ptr<int>(newint(10))会产生一个临时的对象,因为auto_ptr的拷贝构造函数为非常量引用,C++禁止为非常量引用产生临时对象。因为非常量引用可能会修改临时对象中数据成员的值,但只是修改临时对象的数据成员,而该临时对象在执行完该语句后就会调用析构释放。所以在某些函数参数传递时,例如将一个字符串作ch为实参传递给一个string str &,假设string类会调用构造函数将字符串作为构造函数的参数,产生一个临时对象,并将str绑定在该临时对象,此时为非常量引用,如果str对该字符串进行修改,只是修改了临时对象中的字符串,并没有修改ch中的值,并没有到达预期的结果。因此仅当通过传值方式传递对象或传递常量引用参数时,才会发生类型转换。(More Effective C++ Item M20)
struct auto_ptr_ref {
_Tp1 * _M_ptr;
explicit auto_ptr_ref(_Tp1 * __p) : _M_ptr(__p) { }
};
auto_ptr(auto_ptr_ref<element_type> __ref) : _M_ptr(__ref._M_ptr) {
#ifdef DISPLAY
cout << "auto_ptr auto_ptr_ref Constructor" << endl;
#endif
}
template <typename _Tp1>
operator auto_ptr_ref<_Tp1>() {
#ifdef DISPLAY
cout << "operator auto_ptr_ref" << endl;
#endif
return auto_ptr_ref<_Tp1>(this -> release());
}
通过将auto_ptr临时对象转化为auto_ptr_ref(传值)完成拷贝。具体实现如下:
(1)auto_ptr<int>(new int(10))产生临时对象_p,auto_ptr<int> p1 = __p 调用auto_ptr拷贝构造。
(2)auto_ptr的拷贝构造函数中参数类型为auto_ptr_ref<_Tp1>,由于是传值而不是引用,所以可以进行类型转换。
(3)在operator auto_ptr_ref<_Tp1>中,返回 __p._M_ptr,结束__p对空间的拥有权。因为该临时对象在完成拷贝之后,会调用析构函数释放空间,为了避免多次释放同一空间,__p = 0。
(4)tmp作为auto_ptr_ref构造函数的参数,初始化auto_ptr_ref的成员_M_ptr。将auto_ptr_ref的临时对象_r返回。
(5)auto_ptr拷贝构造函数的参数_ref= _r,将_ref._M_ptr赋值给p1._M_ptr,完成拷贝。然后释放__p._M_ptr。由于_r的析构函数为默认的,所以不会释放_r._M_ptr所指向的空间。
p1 =auto_ptr<int>(new int(30));
用临时对象进行赋值操作在类型转换、结束临时对象对空间的拥有权、调用auto_ptr_ref构造函数初始化__ref._M_ptr和p1._M_ptr = __ref._M_ptr的操作一致,只是在处理的时候,赋值操作需要先释放p1原先指向的空间,然后将临时对象对空间的拥有权交给p1。
auto_ptr & operator=(auto_ptr_ref<element_type> __ref) {
if (__ref._M_ptr != this -> get()){
#ifdef DISPLAY
cout << "auto_ptr auto_ptr_ref operator=" << endl;
#endif
delete _M_ptr;
_M_ptr = __ref._M_ptr;
}
}
完整的auto_ptr如下:
#ifndef _AUTO_PTR_H
#define _AUTO_PTR_H
#include <iostream>
#include <assert.h>
using namespace std;
//#define DISPLAY
template <class _Tp1>
struct auto_ptr_ref {
_Tp1 * _M_ptr;
explicit auto_ptr_ref(_Tp1 * __p) : _M_ptr(__p) { }
};
template <class _Tp>
class auto_ptr {
public:
typedef _Tp element_type;
/* default Constructor */
explicit auto_ptr(element_type * __p = 0) : _M_ptr(__p) { }
/* copy Constructor */
auto_ptr(auto_ptr & __a) : _M_ptr(__a.release()) { }
template <class _Tp1>
auto_ptr(auto_ptr<_Tp1> & __a) : _M_ptr(__a.release()) { }
/* overloading operator */
auto_ptr & operator=(auto_ptr & __a) {
if (this != &__a) {
reset(__a.release());
}
return *this;
}
element_type & operator*() const {
assert(_M_ptr != NULL);
return *_M_ptr;
}
element_type * operator->() const {
assert(_M_ptr != NULL);
return _M_ptr;
}
/* release auto_ptr */
element_type * release() {
element_type * tmp = _M_ptr;
_M_ptr = 0;
return tmp;
}
/* reset auto_ptr */
void reset(element_type * __p = 0) {
if (__p != _M_ptr) {
delete _M_ptr;
_M_ptr = __p;
}
}
element_type * get() const {
return _M_ptr;
}
~auto_ptr() {
delete _M_ptr;
}
auto_ptr(auto_ptr_ref<element_type> __ref) : _M_ptr(__ref._M_ptr) {
#ifdef DISPLAY
cout << "auto_ptr auto_ptr_ref Constructor" << endl;
#endif
}
auto_ptr & operator=(auto_ptr_ref<element_type> __ref) {
if (__ref._M_ptr != this -> get()){
#ifdef DISPLAY
cout << "auto_ptr auto_ptr_ref operator=" << endl;
#endif
delete _M_ptr;
_M_ptr = __ref._M_ptr;
}
}
template <typename _Tp1>
operator auto_ptr_ref<_Tp1>() {
#ifdef DISPLAY
cout << "operator auto_ptr_ref" << endl;
#endif
return auto_ptr_ref<_Tp1>(this -> release());
}
template <typename _Tp1>
operator auto_ptr<_Tp1>() {
#ifdef DISPLAY
cout << "operator auto_ptr" << endl;
#endif
return auto_ptr<_Tp1>(this -> release());
}
private:
_Tp * _M_ptr;
};
template<>
class auto_ptr<void> {
public:
typedef void element_type;
};
#endif
根据源码加上自己的理解进行编写,没有进行异常处理,如有不足请指出。