【C++】动态内存管理(new,delete,new[],delete[])

C语言动态内存开辟

 C语言使用malloc/calloc/realloc进行动态内存开辟,malloc/calloc/realloc在堆上开辟一段空间,free将开辟的内存释放掉。

链接
(C语言)动态内存开辟

[注意]
堆上的内存需要用户自己来管理,动态malloc/calloc/realloc的空间,必须free掉,否则会造成内存泄露;栈上空间具有函数作用域,在函数结束后系统自动回收,不用用户管理。栈上,使用_alloc在栈上动态开辟内存,栈上开辟的内存由编译器自动维护,不需要用户显式释放。

C++中动态内存管理

1.new和delete运算符

首先我们先通过一段代码来大概了解一下new,delete,new[],delete[]是怎么使用的。
int* p1 = new int;
//这里是开辟一个单个int型空间(int型为四字节大小)
int* p2 = new int(0);
//开辟一个单个int型空间,并初始化为0
int* p3 = new int[10];
//开辟一段连续空间(10个int型也就是40字节的大小)
delete p1;//释放空间
delete p2;//释放空间
delete p3[];//释放空间
//注意new和delete,new[]和delete[]匹配使用,否则可能出现内存泄漏甚至程序崩溃的问题

2.内存存储方式

    * 栈又叫堆栈,主要存放非静态局部变量、函数参数、返回值等,栈是向下增长的。
    * 内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库,做进程间通信。
    * 堆用于程序运行时动态内存分配,堆是向上增长的。
    * 数据段用于存储全局数据和静态数据。
    * 代码段用于存储可执行的代码、只读常量。

3.深入理解C++动态内存管理

new作用:
 调用operater new 分配空间,调用构造函数初始化对象

这里写图片描述
new源码:

void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
        {       // try to allocate size bytes
        void *p;
        while ((p = malloc(size)) == 0)
                if (_callnewh(size) == 0)
                {       // report no memory
                static const std::bad_alloc nomem;
                _RAISE(nomem);
                }

        return (p);
        }
delete作用:

调用析构函数清理对象,调用operator delete释放空间。

这里写图片描述

delete源码

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;
}
new[]作用:

调用operator new分配空间。调用N次构造函数分别初始化每个对象。

这里写图片描述

new[]源码:

void *__CRTDECL operator new[](size_t count) _THROW1(std::bad_alloc)
    {   // try to allocate count bytes for an array
    return (operator new(count));
    }
delete[]作用:

调用N次析构函数清理对象,调用operator delete释放空间。

这里写图片描述

delete[]源码:

void operator delete[]( void * p )
{
    RTCCALLBACK(_RTC_Free_hook, (p, 0))

    operator delete(p);
}

4.malloc/free和new/delete 之间的区别与联系

* 它们都是动态管理内存的入口。
* malloc/free是C/C++标准库的函数,new/delete是C++操作符。
* malloc/free只是动态分配内存空间/释放空间。而new/delete除了分配空间还会调用构造函数和析构函数进行初始化与清理(清理成员)。
*  malloc/free需要手动计算类型大小且返回值会void*,new/delete可自己计算类型的大小,返回对应类型的指针。

5.总结

* . operator new/operator delete operator new[]/operator delete[] 和 malloc/free用法一样。
* 他们只负责分配空间/释放空间,不会调用对象构造函数/析构函数来初始化/清理对象。
*  实际operator new和operator delete只是malloc和free的一层封装。

思考问题

1.使用new[]的时候,编译器怎么知道要调用多少次malloc函数?

程序示例:

#include<iostream>
#include<Windows.h>

using namespace std;

class Test
{
public:
    Test(int size = 10)
        :_size(size)
    {
        cout<<"Test(int size)" <<endl;
    }
    ~Test()
    {
        cout<<"~Test()"<<endl;
    }
private:
    int _size;
};
int main()
{
    Test *p = new Test[10];
    delete[] p;
    system("pause");
    return 0;
}

运行调试结果:
这里写图片描述

【结论】:
从这里我们可以看出在new[]开辟的这段空间前面还另开辟了一段4个字节的空间,记录了new[]要调用malloc函数的次数。

2.假设没有匹配起来使用这两对new/delete,new[]/delete[],什么情况下程序可以正常运行?什么情况会存在内存泄露?什么情况下程序会崩溃?

正常运行:
当创建的类型是内置类型的时候;
内存泄漏:
当写出如下这类代码时会内存泄漏:

#include<iostream>
#include<Windows.h>

using namespace std;

class Test
{
public:
    Test(size_t size = 10)
        :_size(size)
        ,_a(0)
    {
        _a = new int[size];
        cout<<"Test(size_t size)" <<endl;
    }
    ~Test()
    {
        delete[] _a;
        cout<<"~Test()"<<endl;
    }
private:
    int* _a;
    size_t _size;
};
int main()
{
    Test *p = new Test;
    free(p);//free不会调用析构函数,析构函数里才会delete _a
    system("pause");
    return 0;
}

程序崩溃:
用new[]创建一段连续的空间,如果存在析构函数的话,用free 或是delete来释放这段空间会造成程序崩溃。因为free不会释放p1所指的前四个字节,不会销毁里面定义的空间。delete不会释放p1所指的前四个字节,但会销毁里面定义的空间。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值