一、资源分配即初始化:定义一个类来进行资源的分配和释放,在构造函数完成资源的分配和初始化,在析构函数完成资源的清理,可以保证资源的正确初始化和释放(构造函数负责把资源分配给你,析构函数负责释放资源)
建议:在任何时候都不要使用AutoPtr,除非不用调用拷贝构造、赋值运算符的重载
template<class T>
class AutoPtr
{
public:
AutoPtr(T* ptr = NULL)//外部用户没有提供,默认给成空
//构造函数负责分配资源
:_ptr(ptr)
{
cout << "AutoPtr:" << this<<endl;
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
//析构函数:把资源拿走
~AutoPtr()
{
cout << "~AutoPtr:" << this << endl;
if (_ptr)
delete _ptr;
}
private:
T* _ptr;
};
struct A
{
int _a;
int _b;
int _c;
};
void TestAutoPtr()
{
int *p1 = new int;
*p1 = 10;
AutoPtr<int> ap1(new int);//此时的对象不能直接当作一个指针进行解引用
//使用*或->,需要重载*或->
*ap1 = 10;
A* p2 = new A;
p2->_b = 10;
AutoPtr<A> ap2(new A);
ap2->_b = 10;
delete p1;//在这种方式下,必须手动释放p1和p2
delete p2;
}
int main()
{
return 0;
}
这种智能指针的存在,使得函数返回的位置不需要释放空间,不需要关闭指针,调用析构函数处理。
这种结构存在的缺陷:浅拷贝的方式,拷贝构造后,两个对象会指向同一个空间,释放时会出现问题。【没有把拷贝构造函数实现出来,是一个浅拷贝,浅拷贝导致两个对象共用同一块资源,同一块资源被释放多次,出现问题】
void TestAutoPtr()
{
int *p1 = new int;//先申请一个整型的空间
int *p11(p1);//让p11也指向这个整型的空间
*p1 = 10;//把p1的内容改为10
AutoPtr<int> ap1(new int);//申请一端整型的空间,交给ap1进行管理
AutoPtr<int> ap11(ap1);//用ap1拷贝构造ap11
*ap1 = 10;//
//出了函数的作用域,p1和p2管理的单个的空间已经释放了,接着释放三个类对象
//销毁时先创建的后销毁:先销毁ap2,再销毁ap11,ap11通过ap1拷贝构造
//会出现问题:浅拷贝的方式
A* p2 = new A;
p2->_b = 10;
AutoPtr<A> ap2(new A);
ap2->_b = 10;
delete p1;//在这种方式下,必须手动释放p1和p2
delete p2;
}
此时不能采用深拷贝的方式解决,因为,深拷贝要求ap1拥有资源,要求ap11也拥有资源。这块空间是外部用户申请 的空间,不是当前类申请的空间,这个类只是负责管理空间,没有申请空间的权力,只有释放空间的权力。
2、解决方式:ap1拷贝构造ap11,将ap1的管理控制权交给ap11,将ap1中的资源转移到ap11(当前对象)
添加拷贝构造函数:
//拷贝构造函数
AutoPtr(AutoPtr<T>& ap)
:_ptr(ap._ptr)//先让ap和ptr共用同一块资源
{
//再让ap和ptr脱离关系
ap._ptr = NULL;
}
主函数中:
void TestAutoPtr()
{
int *p1 = new int;//先申请一个整型的空间
int *p11(p1);//让p11也指向这个整型的空间
*p1 = 10;//把p1的内容改为10
AutoPtr<int>