1、旧版auto_ptr的实现方式
最开始auto_ptr的成员变量主要有T* _ptr 和 bool _owner,主要实现原理是在构造对象时赋予其管理空间的所有权,在拷贝或赋值中转移空间的所有权,在析构函数中当_owner为true(拥有所有权)时来释放所有权。
template <class T>
class my_auto_ptr{
private:
T* _ptr;
bool _owner;
public:
my_auto_ptr(T* ptr); //构造函数
my_auto_ptr(my_auto_ptr<T>& ap); //复制构造函数
my_auto_ptr<T>& operator=(my_auto_ptr<T>& ap); //重载赋值运算操作符
T* operator->(); //重载箭头操作符
T& operator*(); //重载解引用操作符
~my_auto_ptr(); //析构函数
};
template<class T>
my_auto_ptr<T>::my_auto_ptr(T* ptr) :_ptr(ptr), _owner(true) {}
template<class T>
my_auto_ptr<T>::my_auto_ptr(my_auto_ptr<T>& ap):_ptr(ap._ptr) {
ap._owner = false;
}
template<class T>
my_auto_ptr<T>& my_auto_ptr<T>::operator=(my_auto_ptr<T>& ap) {
if (this != &ap) {
delete this._ptr;
this._ptr = ap._ptr;
this._own = true;
ap._owner = false;
}
return *this;
}
template<class T>
T* my_auto_ptr<T>::operator->() {
return this->_ptr;
}
template<class T>
T& my_auto_ptr<T>::operator*() {
return *(this->_ptr);
}
template<class T>
my_auto_ptr<T>::~my_auto_ptr() {
if (this->_ptr) {
this->_owner = false;
delete this->_ptr;
cout << "析构了" << endl;
}
}
旧版auto_ptr出现的主要问题:如果拷贝出来的对象比原来的对象先出作用域或先调用析构函数,则原来的对象的_owner虽然为false,但却在访问一块已经释放的空间,原因在于拷贝对象的释放会导致原对象的_ptr指向的内容跟着被释放,这就造成指针的悬挂的问题。
int main() {
my_auto_ptr<int> p1(new int(10));
cout << *p1 << endl;
if (true) {
my_auto_ptr<int> p2(p1);
}
*p1 = 20;;
return 0;
}
2、新版auto_ptr的实现方式
新版auto_ptr的实现方法还是管理空间的所有权转移,但这种实现方法中没有_owner权限拥有者。构造和析构和上述实现方法类似,但拷贝和赋值后直接将_ptr赋为空,禁止其再次访问原来的内存空间,比较简单粗暴。
template<class T>
class you_auto_ptr{
public:
you_auto_ptr(T* ptr); //构造函数
you_auto_ptr(you_auto_ptr<T>& ap); //复制构造函数
you_auto_ptr<T>& operator=(you_auto_ptr<T>& ap); //重载赋值操作运算符
T* operator->(); //重载箭头操作符
T& operator*(); //重载解引用运算符
~you_auto_ptr(); //析构函数
private:
T* _ptr;
};
template<class T>
you_auto_ptr<T>::you_auto_ptr(T* ptr) :_ptr(ptr) {}
template<class T>
you_auto_ptr<T>::you_auto_ptr(you_auto_ptr<T>& ap):_ptr(ap._ptr) {
ap._ptr = NULL;
}
template<class T>
you_auto_ptr<T>& you_auto_ptr<T>::operator=(you_auto_ptr<T>& ap) {
if (this != ap) {
delete this->_ptr;
this->_ptr = ap._ptr;
ap._ptr = NULL;
}
return *this;
}
template<class T>
T& you_auto_ptr<T>::operator*() {
return *(this->_ptr);
}
template<class T>
T* you_auto_ptr<T>::operator->() {
return this->_ptr;
}
template<class T>
you_auto_ptr<T>::~you_auto_ptr() {
if (this->_ptr) {
delete this->_ptr;
this->_ptr = NULL;
}
}
这种实现方式很好的解决了旧版本野指针问题,但是由于它实现了完全的权限转移,所以导致在拷贝构造和赋值之后只有一个指针可以使用,而其他指针都置为NULL,使用很不方便,而且还很容易对NULL指针进行解引用,导致程序崩溃,其危害也是比较大的。
int main() {
you_auto_ptr<int> p1(new int(10));
cout << *p1 << endl;
you_auto_ptr<int> p2(p1);
*p1 = 20;
return 0;
}
auto_ptr的总结
说了这么多,其实最终目的就是千万别用这个已经被C++摈弃的库函数,资源权限的转移带来的是安全性的问题,当你理解了它的使用带来的众多内存泄漏,程序崩溃的实例时,相信你对这个智能指针也必须保持敬畏之心了。