C++内存管理

C++内存管理

C++的内存区域分布情况

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. 栈又叫堆栈–非静态局部变量/函数参数/返回值等等,栈是向下增长的。
  2. 内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口
    创建共享共享内存,做进程间通信。(Linux课程如果没学到这块,现在只需要了解一下)
  3. 堆用于程序运行时动态内存分配,堆是可以上增长的。
  4. 数据段–存储全局数据和静态数据。
  5. 代码段–可执行的代码和只读常量

C语言和C++内存管理的区别

C语言:malloc/realloc/calloc/free

C++: new/delete/new[]/delete[]

C语言的内存管理在C++中依然可以继续使用,但有些场景真的是不尽人意,我们可以选用new和delete来进行内存管理

C++申请内置维护类型空间:

int main() {
	int* p_int = new int;//从堆区申请一个int 的空间,将地址赋值给指针p_int
	*p_int = 20;
	delete p_int;//从堆区释放内存
	int* p_arr = new int[10];//从堆区申请10个int 的连续空间,将首地址地址赋值给指针p_int
	delete[] p_arr;//从堆区释放int数组的内存
	return 0;
}

C++申请自定义类型的空间

class A {
private:
	int _a;
public:
	A() 
	{
		cout << "构造函数" <<endl;
	}
	~A() {
		cout << "析构函数" << endl;
	}
};
int main() {
	A* p_A = new A;
	delete p_A;
	return 0;
}

运行结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

两个全局函数operator new和operator delete函数(重点)

C++里的new和delete是运算符重载的,他们的本质是调用operator new和operator delete函数

operator new函数最终是调用的malloc来开辟的内存,其实C++就是在C语言功能上进行的完善和修改进一步封装

同理delete最终调用的也是free。

下边是源码:

//operator new
_CRT_SECURITYCRITICAL_ATTRIBUTE
void* __CRTDECL operator new(size_t const size)
{
    for (;;)
    {
        if (void* const block = malloc(size))
        {
            return block;
        }

        if (_callnewh(size) == 0)
        {
            if (size == SIZE_MAX)
            {
                __scrt_throw_std_bad_array_new_length();
            }
            else
            {
                __scrt_throw_std_bad_alloc();
            }
        }

        // The new handler was successful; try to allocate again...
    }
}
//operator delete
operator delete: 该函数最终是通过free来释放空间的
*/
void operator delete(void *pUserData)
{
_CrtMemBlockHeader * pHead;
RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));
if (pUserData == NULL)
return;
_mlock(_HEAP_LOCK); /* block other threads */
__TRY
/* get a pointer to memory block header */
pHead = pHdr(pUserData);
/* verify block type */
_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
_free_dbg( pUserData, pHead->nBlockUse );
__FINALLY
_munlock(_HEAP_LOCK); /* release other threads */
__END_TRY_FINALLY
return;
}

通过上述两个全局函数的实现知道,operator new 实际也是通过malloc来申请空间,如果malloc申请空间成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施就继续申请,否则就抛异常。operator delete 最终是通过free来释放空间的。

两个全局函数工作的原理

对单个对象的申请都大同小异,但是对于连续空间比如数组的申请就是我们这次重点要讨论的了。

new T[N]的原理

  1. 调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对象空间的申请
  2. 在申请的空间上执行N次构造函数

delete[]的原理

  1. 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理
  2. 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间

使用里的一些问题

在这里插入图片描述

但是我们不禁会产生一些疑问:

比如

1、 既然C++是兼容C的那么malloc和delete可以混合使用嘛?

2、delete[] 会在结束时候对对象进行析构,那么它是怎么知道要进行多少次析构呢?

3、如果不能以上问题中,两种风格混着使用会引起什么问题呢?

我们将对以上问题 一一详细解答

首先来看第一个:

malloc和delete可以混合使用嘛?

答案是不可以,因为delete会进行析构,而malloc时候都不会调用构造函数来初始化,谈何析构而言呢?

delete[] 会在结束时候对对象进行析构,那么它是怎么知道要进行多少次析构呢?

来看以下代码:

class A {
private:
	int _a;
public:
	A() 
	{
		cout << "构造函数" <<endl;
	}
	~A() {
		cout << "析构函数" << endl;
	}
};
int main() {
	A* a = new A[5];
	delete[] a;
	return 0;
}

我们在vs的调试界面对内存进行观察:

在这里插入图片描述

我们看右边内存里的东西。我们可以观察到下边框起来的成功开辟出来了所需要的空间,但是在这之前注意下上边框里的内容,它里边存放了个数字5。大家可以先合理猜测下。

我们这样用delete[]可以正常释放掉所有空间,看下图。我们可以明确 上边那个5确实是我们开辟出来的

在这里插入图片描述

这里我来提出一个问题,来提醒下大家,我们这里在调试界面是直接输入a来定位内存在0x00FCB524也就是说a指向这个地址,这个地址按道理来讲是首地址,但是a之前还有4个字节来存放了一个5,这里我们合理猜测他就是用来存放析构次数的功能。我们知道C语言是不支持内存的分段式放的,但是a指向的不是首地址的话,那就是delete[]进行了特殊处理,那么我们用C语言的free来释放会引起什么问题呢?看下图:

在这里插入图片描述

显然程序崩溃了。这样上边的第三个问题也就回答了

两种风格绝对不可以乱用,一定要配套使用,因为他们实现原理是不同的,尤其是自定义类型的动态开辟,切记不要乱用。

END

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

栗悟饭&龟波气功

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值