智能指针通过对象管理指针,在构造对象时完成资源的分配及初始化,在析构对象时完成资源的清理及汕尾工作。
因此,可以得到一份简洁版的智能指针代码:
template<class T>
class AutoPtr
{
public:
//构造函数,完成资源的初始化与分配
AutoPtr(T* ptr = NULL)
:_ptr(ptr)
{}
//析构函数,完成资源的清理及汕尾工作
~AutoPtr()
{
if (NULL != _ptr)
{
delete _ptr;
_ptr = NULL;
}
}
private:
T* _ptr;
};
int main()
{
AutoPtr<int> a1(new int(100));
AutoPtr<int> a2(new int(200));
AutoPtr<int> a3(a1);
AutoPtr<int> a4;
a4 = a1;
system("pause");
return 0;
}
a1与a3共同管理一块空间,a2与a4共同管理一块空间,看起来好像没什么问题。但当程序跑起来,出了函数作用域之后就会崩毁
由于没有实现赋值操作符的重载,拷贝构造函数,所以在创建对象时编译器会自动调用默认的拷贝构造和赋值运算符重载。而系统默认的是浅拷贝
a1与a3,a2与a4共同管理同一块空间,一旦出了函数作用域,a3会调用析构函数,delete掉所指向的空间;而当a1调用析构函数时,此时a1所指向的已经是一块非法内存(因为被a3 delete过了),因此当a1再次delete这块空间时,程序就会挂掉。
同样一块空间被delete了两次,所以最终程序会挂掉。
而auto_ptr是怎么解决这个问题的呢——管理权转移
AutoPtr(AutoPtr& a)//拷贝构造
{
//转移管理权
_ptr = a._ptr;
a._ptr = NULL;
}
//赋值运算符重载
AutoPtr &operator=(AutoPtr &a)
{
if (a._ptr != _ptr)
{
AutoPtr tmp(a);
std::swap(_ptr,tmp._ptr);//析构函数去管理tmp
}
return *this;
}
auto_ptr通过转移管理权,来保证在赋值与拷贝时仅管理一份指针,而防止同一块空间释放多次的问题
#include<iostream>
using namespace std;
template<class T>
class AutoPtr
{
public:
//构造函数,完成资源的初始化与分配
AutoPtr(T* ptr = NULL)
:_ptr(ptr)
{}
//析构函数,完成资源的清理及汕尾工作
~AutoPtr()
{
if (NULL != _ptr)
{
delete _ptr;
_ptr = NULL;
}
}
AutoPtr(AutoPtr& a)//拷贝构造
{
//转移管理权
_ptr = a._ptr;
a._ptr = NULL;
}
//赋值运算符重载
AutoPtr &operator=(AutoPtr &a)
{
if (a._ptr != _ptr)
{
AutoPtr tmp(a);
std::swap(_ptr,tmp._ptr);//析构函数去管理tmp
}
return *this;
}
private:
T* _ptr;
};
int main()
{
AutoPtr<int> a1(new int(100));
AutoPtr<int> a2(new int(200));
AutoPtr<int> a3(a1);
AutoPtr<int> a4;
a4 = a1;
system("pause");
return 0;
}