C/C++中的内存管理

发布于:2025-07-24 ⋅ 阅读:(15) ⋅ 点赞:(0)
C/C++ 中程序使用的内存区域

C中的动态内存管理 

malloc

申请 size 大小的空间

int* pi = (int*)malloc(sizeof(int) * 10);

calloc

申请 num 个 size 大小的空间,
并初始化为 0 值
int* pi = (int*)calloc(10, sizeof(int));

realloc

将 ptr 指向的空间,扩容至 size 大小
int* new_pi = (int*)realloc(pi, sizeof(int)*100);

free

释放掉由 malloc、calloc、
realloc 申请的空间
free(new_pi);

小结

C中的动态内存管理方式,不能很好地支持自定义类型,所以 C++ 中有了 new 和 delete

A* a = (A*)malloc(sizeof(A));	// 为 A 类型申请空间,但不能初始化

C++中的动态内存管理

new & delete

    int* pi = new int;	// 申请 1 个 int 类型的空间
	int* pi1 = new int(0);	// 初始化为 0
	int* pi2 = new int[10];	// 申请 10 个 int 类型的空间
	A* pa = new A;	// 申请 1 个 A 类型的空间,并调用默认构造初始化

	delete pi;
	delete pi1;
	delete[] pi2;
	delete pa;    // 调用 A 类的析构函数,并释放空间

使用 new 动态申请的内存,必须使用 delete 释放

与 C 中对动态内存管理方式的区别:

对于自定义类型,new 会开空间 + 调用构造函数初始化,delete 会调用析构函数 + 释放空间。

但是对内置类型,处理基本一样,开空间但不会初始化。

另外,new 在申请空间失败后会抛出异常,需用 try catch 捕获;malloc 申请失败后,会返回 NULL

new[ ] & delete[ ]

	A* pa = new A[10];
	delete[] pa;

new A[n] 和 delete[ ] pa 是对多个对象空间的申请和释放操作,其中,分别调用了 operator new[ ] 与 operator delete[ ] 函数;过程与单个对象空间的申请与释放,基本没有区别。

但是为多个对象开辟和释放空间时,一般 new 会额外开辟空间存取开辟的对象个数(不同编译器的实现方式可能不同),以便 delete 时,编译器知道该释放掉多大空间。

operator new

针对自定义类型,使用 new 创建对象,实际上做了两步操作

(1)调用了底层的 operator new 这个全局函数申请空间

(2)调用该自定义类型的构造函数

如下图(vs中 new 对象,调试时的汇编指令),在整个 new 对象的过程中, call 了两个函数:operator new 和 A 类的默认构造:

借鉴一下C友的源码:

void* __CRTDECL operator new(size_t const size)
{
    for (;;)
    {
        if (void* const block = malloc(size))    // 调用了 malloc
        {
            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 new 函数中,实际调用了 malloc 来申请内存

operator delete

同理,针对自定义类型,C++ 中的 delete 也是分两步走:

(1)调用该类型的析构函数

(2)调用 operator delete 释放申请的空间

void __CRTDECL operator delete(void* const block) noexcept
{
    #ifdef _DEBUG
    _free_dbg(block, _UNKNOWN_BLOCK);
    #else
    free(block);
    #endif
}

operator delete 的源码中,仍然是调用了 free 来释放内存。

operator new[ ] & operator delete[ ]

同单个对象的空间申请与释放步骤一样,多个对象 new A[ ] 和 delete[ ] p 时:

new A[ ] :调用多次operator new[ ] + 构造函数

delete [ ] p :调用多次析构函数 + operator delete[ ]

小结

new 和 delete、malloc 和 free 匹配使用,否则行为将未定义。

new 和 delete、malloc 和 free 共同点:都是从堆上申请空间,并且需要手动释放。

区别:

1、malloc 和 free 时函数,new 和 delete 是操作符;

2、malloc 申请的空间不会初始化,而 new 可以初始化;

3、malloc 申请空间时,需要手动计算大小并传参;而 new 只需要在后面跟上类型以及对象个数;

4、malloc 的返回值为 void* ,需要强制转换指针;而 new 因为后跟类型的原因,不需要转换指针类型;

5、malloc 申请失败返回 NULL,对 malloc 使用必须加判空语句;而 new 需要捕获异常;

6、针对自定义类型,malloc/free 只能开辟空间,不会调用构造函数和析构函数;而 new/delete 会在申请空间时调用构造函数完成对象的初始化,delete 会在释放空间之前调用析构函数完成空间中的资源清理。

思考:new 和 delete 目的就是在面向对象编程中,支持自定义类型对象的空间申请、初始化以及资源释放。


网站公告

今日签到

点亮在社区的每一天
去签到