C++动态内存管理

目录

一、内存的分布:

二、普通的动态内存申请

c语言的动态内存管理。

c++的申请方式:

1、new  int(10)

2、new int [10]

三、在类中的内存管理

1、malloc型在类中:

2、new型在类中的表现

四、异常不安全问题

异常不安全的产生 

解决异常不安全:

1、先申请成功空间再进行delete

 2、先创建一个临时对象,再交换临时对象和原来对象的值

new 和  delete的三种形式

1、  new operator      new操作符 

2、operator   new      操作符new   

3、palcement  new    定位new       (重要)     


一、内存的分布:

内存主要分为三个部分:

二、普通的动态内存申请

c语言的动态内存管理。


void *malloc( size_t size );

可以看到申请出来的值未初始化,都是随机值

calloc():              void *calloc( size_t num, size_t size );

在申请空间的时候会初始化,可以看到确实都为0;

void *realloc( void *memblock, size_t size );

当然,在申请空间以后,肯定要用到free函数,去将申请的空间给释放了(有始有终)

那么问题来了,既然c++是兼容c语言的,既然malloc,realloc,calloc函数已经能够做到内存的管理了,为什么c++还要用别的方法:定义new 和delete 运算符呢?

new 和delete运算符肯定有着别样的优点,接下来就一起来看看吧:

c++的申请方式:

1、new  int(10)

 后面的(10)代表着初始化为10

2、new int [10]

后面的【10】表示的是申请一个数组,大小为10

 当然,这种形式也可以进行初始化,方式是在后面加个{1,2,3,4,5。。。}

了解了new和delete的简单使用方法之后,

我们都知道c++和类是紧密联系的,我们一起来看下类中的内存管理:

看看new和delete在类中有什么优点

三、在类中的内存管理

1、malloc型在类中:

 静态分配的时候,可以看到,可以自动调用构造函数和析构函数。

那如果动态分配呢?

 我们可以发现,在动态分配对象的时候,并没有自动调用构造和析构(静静的来,静静的走)

在使用c语言的方法去动态开辟的时候,仅仅是把对象所需占用的空间去申请出来了,但和构造、析构没有关系

这时候申请出来的对象自然也就没有初始化,是一堆随机值

形式如下:

 这时候要是想要去初始化对象成员就要去额外定义函数:

	void InitTest()
	{
		m_data = 0;
		ptr = (int*)malloc(sizeof(int) * 10);
		assert(ptr != NULL);
	}
	void DestroyTest()
	{
		free(ptr);
	}

 使用这一套流程,可以看到是很复杂的

 那么我们再来看看new在类中的表现:

2、new型在类中的表现

 可以看到,使用new的时候,不仅能够开辟空间,还会自动去调用构造函数去初始化对象。(这就体现了方便性)

过程如图:

1、对于new函数: 先申请对象空间,在调用构造函数去进行对象的初始化

2、对于delete,那就是先调用析构函数摧毁对象,在释放对象空间0

四、异常不安全问题

异常不安全的产生 

之前在运算符重载的篇章中学习了对于string这种对象成员带有指针的情况,拷贝,赋值函数都要深层次的进行

在这里时,我们有新的要注意的地方

对于赋值函数之前的写法如下:

 但实际上这样写是有一定不妥的             (异常不安全)

假如s占据的空间非常大,那么在赋给s2的时候,对于new来说,有可能会申请空间失败

 那么这个时候就会发生问题了:因为在执行new操作之前,就已经把把m_data的空间给delete了,

那么一旦申请空间失败,不仅不能进行赋值,就连原来的数据也没有了。这就会造成异常不安全(指发生异常的时候,

程序运行不安全)

我们想要的是假如new申请不了空间的时候,能够将原本s2中的数据不变,即做到“能够回去”。

有两种办法可以解决这个问题:

解决异常不安全:

1、先申请成功空间再进行delete

先申请一个new_data空间,申请成功以后再将m_data空间给释放掉:

 2、先创建一个临时对象,再交换临时对象和原来对象的值

代码示意图如下:

 在代码中我们发现没有用delete去操作s2的空间,那是不是忘记了呢?

          不是的,高明之处就在这了:因为tmp是一个对象,当脱离他的生成作业域的时候,便会自动调用析构函数,释放他所指向的空间,而这时候他指向的正好是原来s2中m_data的空间,所以就省去写了delete这一步

这里有个重要的思想:借助临时变量去释放原有的空间

 

 其实赋值函数中的交换也可以使用系统提供的交换函数swap去实现

这样的话就会保证异常安全性,因为在实例化对象的时候肯定会申请空间,如果没有空间的话就会实例化失败

那么就没有接下来的操作了,也就不会造成不安全了。

new 和  delete的三种形式

1、  new operator      new操作符 

平时所使用的new就是new操作符,使用的时候会执行两步操作:

1、申请空间

2、调用构造函数去初始化对象

这两个工作必须一全部都执行

2、operator   new      操作符new   

//操作符new,只能申请空间,不用调用构造函数
void* operator new(size_t sz)
{
	void* ptr = malloc(sz);
	return ptr;
}

 可以发现,当调用的时候,并没有自动调用构造函数,只是开辟了空间

3、palcement  new    定位new       (重要)     

先来看看定位new的解释:

                                                 定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象

再来看看下面这个问题

 我们来看下这段代码,因为使用的是malloc,所以对象只是有了空间,但值还是随机值,

这时候要进行*ps=s的时候,就会引发空间的异常,

那要怎样实现呢?

可以使用定位new

这里的new并没有去开辟新的空间,而是调用了拷贝构造函数,构造完成之后,把所构造的对象放到了ps所指的对象空间

定位new在数组中

 这样使用的时候可以看到ar【0】被赋值为了8,但这样去使用的话永远只能把数组0下标定位,

这不是真正的定位,要想真正实现定位肯定离不开c++中的重要方法--------》重载

这时候写重载的时候多了个参数 pos相当于把位置传了进去,如果不单独定义的话就相当于默认为了0位置

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值