1 C++内存分布

        1.又叫堆,栈--非静态局部变量/函数参数/返回值等等,栈是向下增长的。

        2. 内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享共享内存,做进程间通信。(Linux课程如果没学到这块,现在只需要了解一下)

        3. 用于程序运行时动态内存分配,堆是可以上增长的。

        4. 数据段--存储全局数据和静态数据。

        5. 代码段--可执行的代码/只读常量。

        

2 C++内存管理方式

        C语言的内存管理虽然在C++中仍然适用,但是在某些情况下,C语言的内存管理方式使用是有不方便的地方,比如,初始化类,所以,C++提出了它自己独特的内存管理方式。

new和delete

1 使用方法

        1. 变量=new type(初始化) ,delete 变量

        2. 变量=new type[开辟空间个数] {初始化内容},delete[]  变量

2 C++与C内存管理的区别

        1.C++的内存管理的new和delete是关键字而C语言的内存管理malloc,realloc,calloc和free都是函数

        2.C++的内存管理在开辟类的空间和释放类的空间的时候会调用类的构造函数和析构函数而C语言的内存管理函数只开辟空间

3 开辟空间失败处理

        C语言开辟空间失败时,则其开辟空间的函数返回值是NULL空指针,而在C++中它并不是反回空指针而是抛异常而我们只要使用try catch来捕获异常即可不会导致整个程序崩溃便于我们调试

例:

#include <iostream>
using namespace std;

int main()
{
    try
    {
        int a =new int[10] {1,2,7,6,4,4}//没有初始化的默认为0
    }catch(const except& ect)
    {
        cout<<ect.what()<<endl;//输出错误信息方便纠错
    }
    return 0;
}

4 new和delete在开辟内置类型和自定义类型空间的实例

#include <iostream>
using namespace std;

class A
{
public:
    A(int n=1)
       :_aa(n)
    {

    }
    ~A()
    {
        _aa=0;
    }
private:
    int _aa=1;
};;

int main()
{
    //开辟内置类型空间
    int a1=new int(1);//(初始化)
    int* a2=new int[10] {1,2,3,4,5,6,7,8,9,10};//[开辟空间个数] {初始化}
    delete a1;
    delete a2;//开辟多个空间释放要用delete[]


    //开辟自定义类型空间
    A  a2 =new A(1)//(初始化),隐类型转化构造详情请看其他文章
    A*  a3 =new A[3] {1,2,3}//自定义类型的开辟多空间初始化
    return 0;
}

注意:申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用new[]和delete[],注意:匹配起来使用。在申请自定义类型的空间时,new会调用构造函数,delete会调用析构函数,而malloc与free不会。


3 C++中new和delete的底层原理

1 operator new与operator delete函数

        new和delete是用户进行动态内存申请和释放的操作符,operator new 和operator delete是系统提供的全局函数,new在底层调用operator new全局函数来申请空间,delete在底层通过operator delete全局函数来释放空间。

operator new在库中的实现原理:

/
*
operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间
失败,尝试执行空 间不足应对措施,如果改应对措施用户设置了,则继续申请,否
则抛异常。
*/
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
        // 如果申请内存失败了,这里会抛出bad_alloc 类型异常
        static const std::bad_alloc nomem;
        _RAISE(nomem);
    }
    return (p);
}

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;
} /
*
free的实现
*/
#define free(p) _free_dbg(p, _NORMAL_BLOCK)

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

2 实现原理

 1 内置类型  

        如果申请的是内置类型的空间,new和malloc,delete和free基本类似,不同的地方是: new/delete申请和释放的是单个元素的空间,new[]和delete[]申请的是连续空间,而且new在申请空间失败时会抛异常,malloc会返回NULL。

2 自定义类型

new的原理

1. 调用operator new函数申请空间

2. 在申请的空间上执行构造函数,完成对象的构造

delete的原理

1. 在空间上执行析构函数,完成对象中资源的清理工作

2. 调用operator delete函数释放对象的空间

new T[N]的原理

1. 调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对象空间的申请

2. 在申请的空间上执行N次构造函数

delete[]的原理

1. 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理

2. 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间

注意:new是先开辟空间再调用构造函数,delete是先调用析构函数再销毁空间

4 定位new表达式(placement-new)  (了解)

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

使用格式:

new (place_address) type或者new (place_address) type(initializer-list) place_address必须是一个指针,initializer-list是类型的初始化列表

使用场景:

定位new表达式在实际中一般是配合内存池使用。因为内存池分配出的内存没有初始化,所以如果是自定义类型的对象,需要使用new的定义表达式进行显示调构造函数进行初始化。

例:

#include <iostream>
using namespace std;

class A
{
public:
    A(int n=1)
       :_aa(n)
    {

    }
    ~A()
    {
        _aa=0;
    }
private:
    int _aa=1;
};

int main()
{
    A * a =(A*)malloc(sizeof(A));//此时开辟空间但是没有初始化就可以用new重定位
    new(a)A(2);//用new重定位并且初始化
    return 0;
}

5 C++与C语言混用和C++内存管理使用不规范发生的问题

1 C语言与C++内存管理函数混用

        如果开辟空间是内置类型则没有什么关系,但是如果是自定义类型并且这个类里开辟了空间,则在使用时不会调用构造函数与析构函数可能会导致内存泄露等问题

2  C++内存管理使用不匹配

1 new 与delete[ ]

        delete[ ]会通过记录长度来释放空间。如果是内置类型则程序可以正常运行,但是如果是内置类型会调用多次析构函数会对空间多次释放会报错

2 new[ ]与delete

        new[ ]在开辟空间时,会而外多开一个空间记录开辟空间元素个数,但是delete也可以正常释放空间,但是如果没有定义析构函数则不会多开字节存储数据个数所以这用delete释放空间会出错

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐