当前位置: 首页 > article >正文

C++——智能指针 auto_ptr

一、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;
}

http://www.lryc.cn/news/2401630.html

相关文章:

  • .Net Framework 4/C# System.IO 命名空间(文件的输入输出)
  • 图像分类进阶:从基础到专业 (superior哥AI系列第10期)
  • 性能优化之SSR、SSG
  • 【C语言】字符与字符串
  • 经典算法:回文链表
  • uboot移植之GPIO上电初始状态的调整
  • PasteForm(ABP)框架之实现更加灵活的类似多租户的归属过滤功能,比如只能查看自己的相关数据
  • 本地id_rsa.pub输入到服务器~/.ssh/authorized_keys后,依然需要输入密码的解决办法
  • 【设计模式-3.7】结构型——组合模式
  • Unity Mac 笔记本操作入门
  • 实时数据仓库是什么?数据仓库设计怎么做?
  • Linux(12)——基础IO(下)
  • WPF可拖拽ListView
  • rocketmq索引
  • [蓝桥杯]倍数问题
  • 定时任务的 cron 表达式
  • 【MySQL】 约束
  • MySQL 的 redo log 和 binlog 区别?
  • 前端vue打开多个窗口,关闭窗口后才继续执行后续逻辑
  • 「深度拆解」Spring Boot如何用DeepSeek重构MCP通信层?从线程模型到分布式推理的架构进化
  • 如何避免在前端项目中出现重复的第三方依赖包?
  • Java开发中复用公共SQL的方法
  • 【西门子杯工业嵌入式-2-点亮一颗LED】
  • 代码随想录算法训练营第60期第五十五天打卡
  • 重磅更新! 基于Gemini 2.5 Pro打造的AI智能体PlantUML-X上线!
  • [5-02-04].第01节:Jmeter环境搭建:
  • AI智能推荐实战之RunnableParallel并行链
  • windows server2019 不成功的部署docker经历
  • Gemini开源项目DeepResearch:基于LangGraph的智能研究代理技术原理与实现
  • React状态管理Context API + useReducer