一、RAII思想的引入
#include <iostream>
using namespace std;#if 0
// C++中动态申请的资源需要用户自己手动释放
// 如果操作不当,容易造成内存泄漏
// 能否做到让资源自动被释放:RAII
// RAII : 将资源交给对象管理,对象被销毁时自动调用析构函数可以在析构函数中将资源释放掉template<class T>
class smart_ptr
{
public:smart_ptr(T* ptr = nullptr): _ptr(ptr){}// 具有指针类似的效果T& operator*(){return *_ptr;}T* operator->(){return _ptr;}~smart_ptr(){if (_ptr){delete _ptr;_ptr = nullptr;}}T* Get(){return _ptr;}private:T* _ptr;
};void TestSmartPtr1()
{//int* p = new int(10);//smart_ptr<int> sp(p);// ...//delete p;smart_ptr<int> sp(new int(10));*sp = 100;// ...
}struct A
{int a;int b;int c;
};void TestSmartPtr2()
{smart_ptr<int> sp1(new int(10));*sp1 = 100;smart_ptr<A> sp2(new A());sp2->a = 10;sp2->b = 20;sp2->c = 30;
}// 上述smart_ptr已经很好了,达到了刚开始的需求
// 新的问题:类中涉及到资源的管理时,如果没有显式实现拷贝构造 已经 赋值运算符重载
// 则编译器会以浅拷贝的方式实现,smart_ptr就会有问题
// 解决:能够深拷贝解决吗? 答案:不可以
int main()
{// TestSmartPtr1();TestSmartPtr2();return 0;
}
#endif
二、对于memory库中auto_ptr的使用
// 智能指针:对原生态指针进行了封装,以类的方式管理用户的资源,在析构方法中将资源释放掉
// RAII + 具有指针类似的行为 + 如何解决浅拷贝的问题
// 因此:解决深拷贝方式的不同,实现了不同版本的智能指针// 第一种智能指针
// C++98 auto_ptr 原理:
// RAII + 具有指针类似的行为 + 资源转移来解决浅拷贝问题的
#include <memory>#if 0
class A
{
public:A(){cout << "A::A()" << endl;}~A(){cout << "A::~A()" << endl;}int _a;int _b;
};void TestAutoPtr()
{auto_ptr<A> ap1(new A());ap1->_a = 10;ap1->_b = 20;// 当ap1拷贝构造ap2时,ap1会将自己管理的资源// 转移给ap2,然后ap1不在管理了,即:指向空auto_ptr<A> ap2(ap1);ap2->_a = 100;ap2->_b = 200;// ap1->_a = 10; // 运行崩溃:因为ap1将资源转移走之后指向NULLauto_ptr<A> ap3;// 当ap2给ap3赋值时,ap2会将自己管理的资源// 转移给ap3,然后ap2不在管理资源了,即:指向空ap3 = ap2;A* pa1 = new A();A* pa2 = nullptr;pa2 = pa1;pa1->_a = 10;pa2->_b = 20;
}int main()
{TestAutoPtr();return 0;
}
#endif
三、实现自己自己的auto_ptr
#if 0
namespace bite
{template<class T>class auto_ptr{public:// RAIIauto_ptr(T* ptr = nullptr): _ptr(ptr){}~auto_ptr(){if (_ptr){delete _ptr;_ptr = nullptr;}}// 具有指针类似的行为T& operator*(){return *_ptr;}T* operator->(){return _ptr;}// 资源转移auto_ptr(auto_ptr<T>& ap): _ptr(ap._ptr){ap._ptr = nullptr; 资源转移体现在对用来赋值的旧对象的指针置空} auto_ptr<T>& operator=(auto_ptr<T>& ap){if (this != &ap){if (_ptr) 新对象指针有内容的话,需要先进行置空处理。{delete _ptr;}_ptr = ap._ptr; 利用旧对象指针给新对象指针赋值ap._ptr = nullptr; 同样是对旧对象的指针置空}return *this;}private:T* _ptr;};
}
#endif
四、auto_ptr版本二:加入资源权限的转移
// C++98中auto_ptr的改造:
// RAII + 具有指针类似的行为 + 解决浅拷贝的方式:资管管理权限的转移
// 资管管理权限: 对资源释放的权限namespace bite
{template<class T>class auto_ptr{public:// RAIIauto_ptr(T* ptr = nullptr): _ptr(ptr), _owner(false){if (_ptr){_owner = true;}}~auto_ptr(){if (_ptr && _owner){delete _ptr;_ptr = nullptr;_owner = false;}}// 具有指针类似的行为T& operator*(){return *_ptr;}T* operator->(){return _ptr;}// 资源转移auto_ptr(const auto_ptr<T>& ap): _ptr(ap._ptr), _owner(ap._owner){ap._owner = false;}auto_ptr<T>& operator=(const auto_ptr<T>& ap){if (this != &ap){if (_ptr && _owner){delete _ptr;}_ptr = ap._ptr;_owner = ap._owner;ap._owner = false;}return *this;}private:T* _ptr;mutable bool _owner; // 如果为true,表明该对象具有释放资源的权限};
}class A
{
public:A(){cout << "A::A()" << endl;}~A(){cout << "A::~A()" << endl;}int _a;int _b;
};void TestAutoPtr1()
{bite::auto_ptr<A> ap1(new A());ap1->_a = 10;ap1->_b = 20;// 当ap1拷贝构造ap2时,ap1会将自己管理的资源// 转移给ap2,然后ap1不在管理了,即:指向空bite::auto_ptr<A> ap2(ap1);ap2->_a = 100;ap2->_b = 200;ap1->_a = 10; // 运行成功bite::auto_ptr<A> ap3;// 当ap2给ap3赋值时,ap2会将自己管理的资源// 转移给ap3,然后ap2不在管理资源了,即:指向空ap3 = ap2;A* pa1 = new A();A* pa2 = nullptr;pa2 = pa1;pa1->_a = 10;pa2->_b = 20;delete pa1;
}void TestAutoPtr2()
{bite::auto_ptr<A> ap1(new A());ap1->_a = 10;ap1->_b = 20;if (true){bite::auto_ptr<A> ap2(ap1);ap1->_a = 100;ap2->_b = 200;}// 当if结束时,ap2,退出了自己的程序范围,调用析构函数,ap2将资源释放了// 因此ap1内部的指针就变成了野指针ap1->_a = 1000;ap1->_b = 2000;
}// C++标准建议:在什么情况下都不要使用auto_ptr
int main()
{// TestAutoPtr1();TestAutoPtr2();return 0;
}