c++中的内存管理

C/C++内存分布

  1. 栈:非静态局部变量,函数参数,返回值等,栈是向下增长的
  2. 内存映射段:装载一个共享的动态内存库
  3. 堆:用于程序运行时动态内存分配,可以向上增长
  4. 数据段:存储全局变量和静态数据
  5. 代码段:可执行的代码、只读常量

C语言中内存管理方式

malloc:只进行空间申请,不进行初始化。

calloc:进行空间申请+零初始化。

realloc:第一个参数为nullptr/NULL,功能等价于malloc。

int* ptr=(int*)realloc(nullptr, sizeoff(int));

调整空间大小:1.直接原地调整大小 2.重新开空间:重新申请空间,内容拷贝,释放原有空间。

int* ptr2=(int*)realloc(ptr, sizeoff(int)*4);

传入realloc中的空间后需不需要显式释放,会导致二次释放的问题。

new / delete 操作内置类型

申请空间

int* ptr1 = new int;//动态申请一个int类型的空间
int* ptr2 = new int(10);//动态申请一个int类型的空间并初始化为10
int* ptr3 = new[10];//动态申请10个int类型的空间
  • 单个类型的空间:new + 类型
  • 连续空间:new + 类型[个数]
  • 单个类型空间申请 + 初始化:new + 类型(初始值)

释放空间:

delete ptr1;
delete ptr2;
delete[] ptr3;
  • 单个空间delete 指针
  • 连续空间:delete[ ] 指针

new / delete操作自定义类型

动态创建自定义类型对象:

class Date
{
public:
  Date(int year)
  {
    _year = year;
  }
private:
  int _year;
};

void test()
{//new:动态开空间 + 调用构造函数初始化
  Date* pd1 = new Date(2020);
  Date* pd2 = new Date(2019);//调用默认构造:无参构造,全缺省构造
  Date* pd3 = new Date[10];
}
  • 申请单个空间:new 自定义类型(参数列表),调用构造函数初始化
  • 申请连续空间:new 自定义类型[个数] , 自动调用默认构造进行初始化,如果没有则编译器报错

释放自定义类型的空间:

delete pd1;//调用一次析构 + 释放空间
delete pd2;//调用一次析构 + 释放空间
delete[] pd3;//调用十次析构,因为Date[10] + 释放空间
  • delete:调用析构函数清理资源 + 释放空间
  • 连续空间:调用N次析构+释放空间

申请和释放操作匹配使用:malloc free, new delete, new[ ]delete[ ]。

operator new 与 operator delete函数

void* operator new(size_t n)
  • 不是运算符重载函数,而是一个全局变量。
  • 使用方式和malloc类似
  • 封装malloc + 异常处理机制

new的执行过程:operator new–>mallow–>构造函数

申请失败会抛出bad_alloc类型异常

void operator delete(void* ptr)
  • 不是运算符重载函数
  • 使用方式和free类似
  • 封装free

只有自定义类型才会调用构造函数和析构函数

delete的执行过程(自定义类型):析构–> operator delete–>free

operator new 与 operator delete的类专属重载

struct Node
{
public:
  Node()
  {
    cout << "Node()" << endl;
  }
  void operator new(int data)
  {
    void* p = nullptr;
    p = allocator<Node>().allocate(1);
    cout << "mem pool allocate" << endl;
    return p;
  }
  void operator delete(Node* ptr)
  {
    allocator<Node>().deallocate((Node*)ptr, 1);
    cout << "mem pool deallocate" << endl;
  }
private:
  int _data;
  Node* _next;
};

void test()
{
  Node* np1 = new Node;
  Node* np2 = new Node[10];
  
  delete np1;
  delete[] np2;
}

new / delete 原理

new / delete: 内置类型

  • new : operator new --> malloc 失败抛异常
  • delete : operator delete --> free
  • new [] : operator new[] --> operator new --> malloc
  • delete [] : operator delete[] – > operator delete --> free
  • 和malloc区别:new空间申请失败抛异常,malloc空间申请失败返回空指针
  • 和free区别:没有本质区别,delete封装了free操作

new / delete: 自定义类型

  • new : operator new --> malloc --> 构造函数 失败抛异常
  • delete : 析构函数 --> operator delete --> free
  • new [] : operator new[] --> operator new --> malloc --> N此构造函数
  • delete [] : N次析构函数 --> operator delete[] – > operator delete --> free
  • 和malloc区别:new空间申请失败抛异常,malloc空间申请失败返回空指针,new会调用自定义类型的构造函数,完成初始化,malloc不会。
  • 和free区别:delete会调用自定义类型的析构函数,完成资源清理的工作,free不会

malloc/free和new/delete的区别

malloc/free和new/delete

共同点是:都是从堆上申请空间,并且需要用户手动释放

不同的地方是:

  1. malloc和free是函数,new和delete是操作符。
  2. malloc申请的空间不会初始化,new可以初始化。
  3. malloc申请空间时,需要手动计算空间大小并传递,new只需在其后跟上空间的类型即可。
  4. malloc的返回值为void*,在使用时必须强转,new不需要,因为new后跟的是空间的类型。
  5. malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要,但是new需要捕获异常。
  6. 申请自定义类型对象时,malloc/free只会开辟空间,不会调用构造函数与析构函数,而new在申请空间后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理。

new定位表达式:new(地址)类型(参数列表)

在已经开好的空间上显示调用构造函数

new(pd)Date(2030);

Date* pd = (Date*)malloc(sizeof(Date));
new (pd)Date(2030);
Date* pd2 = (Date*)malloc(sizeof(Date));
new (pd2)Date;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值