第37课 智能指针分析(指针特征操作符( -> 、 *)重载)
1. 永恒的话题:内存泄漏
(1)动态申请堆空间,用完后不归还
(2)C++语言中没有垃圾回收的机制
(3)指针无法控制所指堆空间的生命周期------------指针是变量,可以指向内存堆空间,但是无法控制所指堆空间的生命周期
说明内存泄漏:
#include<iostream>
#include<string> using namespace std; class Test
{
int i; public: Test(int i)
{
this->i = i;
} int value()
{
return i;
} ~Test()
{
}
}; int main()
{
for (int i = ; i < ; i++)
{
Test* p = new Test(i); //P指向堆空间的对象
//指针是局部变量for()循环之后消失,但是指针开辟的空间没有进行释放 内存泄漏
//长时间运行会出现Bug cout << p->value() << endl; } return ;
}
2. 深度的思考:我们需要什么?
(1)需要一个特殊的指针,指针生命期结束时主动释放堆空间
(2)一片堆空间最多只能由一个指针来标识------------避免内存多次释放
(3)杜绝指针运算和指针比较-----------(因为只有一个该类对象的指针能指向堆空间,避免指针越界,野指针)
3. 解决方案
定义一个对象,让对象取模拟真正意思上的指针行为---------对象代替指针,称该对象为智能指针 -------智能指针本质:是个对象
(1)重载指针特征操作符( -> 和 * )
(2)只能通过类的成员函数重载
(3)重载函数不能使用参数
(4)只能定义一个重载函数
(5)注意:智能指针只能用来指向堆空间中的对象或变量(不能指向栈)
实验:(1)实现特殊的指针,指针生命期结束时主动释放堆空间
#include<iostream>
#include<string> using namespace std; class Test
{
int i;
public:
Test(int i)
{
cout <<"Test (int i)"<< endl; this->i = i;
}
int value()
{
return i;
}
~Test()
{
cout << "~Test ()" << endl;
} }; //智能指针 本质是对象--------首先创建智能指针类
class Pointer
{
Test* mp; //指针mp指向对象Test,用于保存要被管理对象的指针 public: //构造函数被堆空间上内存地址初始化 Pointer(Test* p = NULL) //指针被堆空间上的地址初始化---参数Test*指针
{
mp = p;
} //重载->操作符 Test* operator -> () //不能使用参数,所以也就只能定义一个重载函数
{
return mp; //返回成员指针
} //重载*操作符 Test& operator * () //不能使用参数,所以也就只能定义一个重载函数
{
return *mp; //*作用指针意义:返回当前指针所指变量或对象
} ~Pointer()
{
delete mp; //智能指针被析构时,同时删除其所管理的Test类的对象,释放成员指针指向的堆空间
}
}; int main()
{
for (int i = ; i < ; i++)
{
// Test* p = new Test(i); //那么就可以用类对象名代替指针 Pointer p = new Test(i); //可以动态的将申请的空间释放 cout << p->value() << endl; // }
return ;
}
实现:一片堆空间最多只能由一个指针来标识------------避免内存多次释放
不进行指针运算和比较
方法:重载赋值操作符和拷贝构造
#include<iostream>
#include<string> //智能指针 本质是对象
using namespace std; class Test
{
int i;
public:
Test(int i)
{
cout <<"Test (int i)"<< endl;
this->i = i;
}
int value()
{
return i;
}
~Test()
{
cout << "~Test (int i)" << endl;
} }; class Pointer
{
Test* mp; //数据成员为指针 public: Pointer(Test* p = NULL) //构造函数被堆空间上内存地址初始化
{
mp = p;
} // 实现一片堆空间最多只能由一个指针标识 杜绝多次释放 //拷贝构造函数
Pointer(const Pointer& obj) //自定义深拷贝构造函数
{
// delete mp; //拷贝构造阶段,mP野指针不能删除---内存错误 mp = obj.mp; //当前对象的成员指针mp指向初始化对象的成员指针所对应的堆空间---两个指针指向一片内存空间
//初始化对象把他指向的堆空间完全交给当前对象-----------即保证只有一个智能指针指向同一片内存 const_cast<Pointer&>(obj).mp = NULL; //所有权的传递,自己置空 const_cast去除只读属性
} //赋值操作符重载函数
Pointer& operator=(const Pointer& obj) // 1,返回值类型一定是引用Test&为了连续赋值 2,参数是const引用类型
{
//进行赋值操作
if (this != &obj) //3,赋值操作符不是自赋值a=a,要避免赋值,通过This判断,this指向当前对象的地址和参数地址不同才进行赋值操作
{
delete mp; mp = obj.mp; //保证赋值操作时,只能由一个智能指针指向同一堆空间 const_cast<Pointer&>(obj).mp = NULL;
}
return *this; //4,返回当前对象地址
} //重载指针特征操作符
Test* operator -> ()
{
return mp; //返回成员指针
}
Test& operator * ()
{
return *mp; //返回当前指针所指变量或对象
} bool isNull() //判断当前智能指针是否为空
{
return(mp == NULL);
} ~Pointer()
{
delete mp;
}
}; int main()
{
Pointer p1 = new Test(); //定义智能指针P1 cout << p1->value() << endl; // Pointer p2 = p1; //定义智能指针P2,用p1进行初始化,p1管理的堆空间转给P2 //不能指针比较的指针运算
// p2++;
// if(p1==p2) cout << p1.isNull() << endl; //1空 p1指向NULL,不再指向原来的堆空间 cout << p2->value() << endl; //0 p2接管P1指向的堆空间------管理92行堆对象
//p2++;不重载++,因为每次只能一个智能指针指向堆空间,这种++操作没意义
//p2智能指针生命期结束,会自动释放接管的堆空间
return ; }
//输出结果:
//Test(int i)
//5
//1
//5
//~Test()
存在问题: 智能指针对应的类只能指向Test固定的类类型,不能指向其他类型,能不能指向各类他能管理的类类型------以后会学到模板实现
4. 小结
掌握智能指针的创建
智能指针在自己生命周期结束,自动释放所指的内存空间
要求c++避免使用原生指针,那么以后就可以使用智能指针
(1)指针特征操作符( -> 和 * )可以被重载
(2)重载指针特征符能够使用对象代替指针
(3)智能指针只能用于指向堆空间中的内存
(4)智能指针的意义在于最大程度的避免内存问题
第37课 智能指针分析(指针特征操作符( -> 、 *)重载)的更多相关文章
- C++语言中数组指针和指针数组彻底分析
################################# ## 基本知识 ## ...
- 不可不表的OSG智能指针之强指针与弱指针 《转载》
不可不表的OSG智能指针之强指针与弱指针 <转载> 使用OSG的人都知道OSG的内存管理方式采用了智能指针,通过智能指针的方式让OSG自己处理对象的销毁工作.在OSG中有两个智能指针类型, ...
- c++ 智能指针、函数指针和指针函数
智能指针: 1.内存泄漏memory leak :是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄漏似乎不会有大的影响,但内存泄漏堆积后的后果就是内存溢出. 2.内存溢出 out of me ...
- C/C++指针的指针(**p)和指针的引用(*&)使用案例分析
#include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <stdlib.h> ...
- C指针分析详解
局部变量和全局变量初始化区别: 局部变量,在未初始化情况下,初值为随机值.C规范对该初值并没有做规定,具体实现由编译器决定.如VC/VS等编译器,会将初始值值为0xCCCCCCCC, 而GCC等编译器 ...
- C语言指针分析
/*************1*************/ int p; //p是一个普通的整型变量. /*************2*************/ int *p; //p与*结合,说明 ...
- 让你不再害怕指针——C指针详解(经典,非常详细)
http://blog.csdn.net/soonfly/article/details/51131141 前言:复杂类型说明 要了解指针,多多少少会出现一些比较复杂的类型,所以我先介绍一下如何完全理 ...
- 10深入理解C指针之---指针运算和比较
该系列文章源于<深入理解C指针>的阅读与理解,由于本人的见识和知识的欠缺可能有误,还望大家批评指教. 指针运算有很多种,主要有指针的声明*.指针的解引*.指针指向(*).或->.指针 ...
- C与指针(结构体指针,函数指针,数组指针,指针数组)定义与使用
类型 普通指针 指针数组(非指针类型) 数组指针 结构体指针 函数指针 二重指针 定义方式 int *p; int *p[5]; int (*p)[5]; int a[3][5]; struct{.. ...
随机推荐
- mybatis源码配置文件解析之五:解析mappers标签流程图
前面几篇博客分析了mybatis解析mappers标签的过程,主要分为解析package和mapper子标签.补充一张解析的总体过程流程图,画的不好,多多谅解,感谢.
- python数据结构(一)
collections --容器数据类型,collections模块包含了除内置类型list,dict和tuple以外的其他容器数据类型. Counter 作为一个容器可以追踪相同的值增加了多少次 # ...
- Redis 6.0 访问控制列表ACL说明
背景 在Redis6.0之前的版本中,登陆Redis Server只需要输入密码(前提配置了密码 requirepass )即可,不需要输入用户名,而且密码也是明文配置到配置文件中,安全性不高.并且应 ...
- Linux服务器定时脚本
crontab -e 进入编辑模式,同vi编辑器操作. 用户所建立的crontab文件中,每一行都代表一项任务,每行的每个字段代表一项设置,它的格式共分为六个字段,前五段是时间设定段,第六段是要执行的 ...
- 在页面制作的时候常用的html页面滚动加载,可视区域判断方法
演示图 考虑2个情况一种情况初始状态下 滚动到在中间区域的时候,这时上半部分看不见的元素就不给字体添加红色一种情况是,从头向下看的. 代码 .ss li { margin: 40px; } <d ...
- HTML5(五)Geolocation
HTML5 Geolocation 定位用户的位置 HTML5 Geolocation API 用于获得用户的地理位置. 鉴于该特性可能侵犯用户的隐私,除非用户同意,否则用户位置信息是不可用的. 注意 ...
- DP没入门就入土
写在前面 记录最近刷的DP题 以及 打死都不可能想到状态设计DP系列 汇总 洛谷 P6082 [JSOI2015]salesman 树形\(\texttt{DP}\) + 优先队列 比较容易看出来这是 ...
- Rust String(官方文档翻译)
学习Rust,官方文档全英文,查询不太方便,索性直接翻译完,方便查询使用.有需要自由转载,本人英文水平有限,文档是在谷歌翻译的基础上加个人理解完成,不敢保证正确.文档翻译错误的地方欢迎指出: 原文地址 ...
- day76 vue框架入门
目录 一.vue.js快速入门使用 1 vue.js库的下载 2 vue.js库的使用 3 vue.js的M-V-VM思想 4 显示数据 二.常用指令 1 操作属性 2 事件的绑定 3 样式操作 3. ...
- day20 函数收尾+面向过程+模块
目录 一.算法(二分法) 二.面向过程与函数式 1 编程范式/思想 2 面向过程 3 函数式 3.1 匿名函数与lambda 三.模块 1 什么是模块 2 为何要有模块 3 怎么用模块 3.1第一次导 ...