[C++]__动态内存管理__

本文介绍了C++中的内存管理技巧,包括使用new/delete与malloc/free的区别,如何为内置及自定义类型动态分配空间,并探讨了operator new与operator delete的用法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

动态内存管理

  • 题外知识点

struct在c语言中,如果不进行typedef,则结构体的名字是struct A。

而在c++中,不用typedef,也可以直接使用A a;在c++中,struct可以当做是类,只是与class的区别是:如果在类class中不声明访问限定符,则默认为private,而在struct中,默认为public。


在c++中,内置类型也有构造函数。

int i = 0;
i = int();//i=0,i匿名对象
i = int(20);//i=20
  • 在c语言中动态开辟空间

使用malloc、calloc、relloc、free等库函数。

malloc、calloc和realloc的区别和联系

  • 在c++中动态开辟空间

可以使用malloc、calloc、relloc、free,但是c++有属于自己的开辟空间的操作符new和delete

new/delete动态管理对象。

new[]/delete[]动态管理对象数组。

一定要匹配使用!一定要匹配使用!一定要匹配使用!

否则可能会出现内存泄漏等巨大的损失。

  • ​ 使用内置类型开辟空间。
void test1() {
//开辟空间
    int* p1 = new int;    //单指定为int类型,但是不初始化,还是随机值。
    int* p2 = new int(10);//指定为int类型且初始化值为10。
    int* p3 = new int[10];//指定为int类型,不是初始化,而是说明了申请的int的大小的空间为10个。
//释放空间
    delete p1;
    delete p2;
    delete[] p3;
}
  • ​ 使用自定义类型开辟空间
class A {
public:
    A(size_t size = 10)//构造函数
        : _size(size)
        , _a(0) {
        cout << "A(size_t size)" << endl;
        if (_size > 0) {//如果输入的size大于零,则开辟一段类型为int的size大小的空间
            _a = new int[size];
        }
    }
    ~A() {//析构函数
        cout << "~A()" << endl;
        if (_a) {
            delete[] _a;//释放a
            _a = 0;
            _size = 0;
        }
    }
private:
    int*_a;
    size_t   _size;
};
void test2() {
    A* p4 = new A;
    A* p5 = new A(10);
    A* p6 = new A[10];

    delete p4;
    delete p5;
    delete[] p6;
}
  • 比较

malloc和free只负责开辟空间。

new和delete不仅开辟空间,还会调用构造函数和析构函数。(建议在c++中尽量使用)

  • new是先申请空间,后调用构造函数。
    • 因为需要先申请到空间,才能在那个空间上构造对象。
  • delete是先调用析构函数,再去释放空间。

    • 如果先释放空间,析构函数就找不到需要析构的对象了。

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

//定义
void * operator new (size_t size); 
void  operator delete (size_t size); 
void * operator new[](size_t size); 
void  operator delete[] (size_t size);
//使用
int* p1 = (int*)operator new(4);
operator delete p1;

标准库函数operator new和operator delete的命名容易让人产生误解,与其他的operator函数(例如operator=)不同,这些函数没有重载new和delete表达式,实际上,我们不能重定义new和delete表达式的行为。

通过调用operator new函数执行new表达式获得内存,并接着在内存中构造一个对象。

通过撤销一个对象执行delete表达式,并接着调用operator delete函数,以释放该对象使用的内存。

这里写图片描述

这里写图片描述

  • 思考

在这里,为什么我们不写delete[10],编译器也知道要调用10次析构函数呢?
这里写图片描述


如果开辟空间和释放空间的操作符不匹配会发生什么情况呢?

A* p0 = new A;
free(p0);//程序不会崩,因为虽然仅仅只是free没有析构,但是没有析构程序不一定会崩。
delete[] p0;//程序会崩,此时由上图可以知道,首先我们不会多开辟A大小的byte,但只要执行delete[],
            //就会向前找A大小的byte,此时就是一种越界行为,程序就会崩溃。

A* p1 = new A[10];
free(p1);//程序会崩,从哪里申请的内存,就要从哪里释放。
delete p1;//程序会崩,因为释放的位置错了,应该从p1前几个字节开始释放。

int* p2 = new int[10];
delete p2;//程序不会崩,在这里使用内置类型申请空间的时候,不会多开辟4个字节,就不需要告诉delete要调用几次析构函数。
  • 严格来说,new[]一定会多开辟空间,告诉delete需要调用多少次析构函数,当编译器识别到析构函数可掉可不调(内置类型)时,会优化,就不调用析构函数了。
  • 总而言之,多不多开辟空间,取决于调不调用析构函数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值