[c++]动态分配内存和内存泄漏

版权声明:转载请注明出处 https://blog.csdn.net/weixin_40937100/article/details/88848886

动态分配内存


1. new 和 delete

函数原型:
void *operator new(size_t); //allocate an object
void *operator delete(void *); //free an object

1.1 new和delete的运行机制(单个对象)

以类A为例:

class A
{
public:
    A(int v) : var(v){
        fopen_s(&file, "test", "r");
    }
    ~A(){
        fclose(file);
    }
private:
    int var;
    FILE *file;
};

当我们用new创建一个A类的指针数组时,new返回的是指向内存空间的A类型的指针

class *pA = new A(10);

背后完成的工作是
在这里插入图片描述
new的工作有以下几点:

  1. 由于A类的大小是8 Bytes(参考《深入C++对象模型》),那么new函数就会开辟一个8 Bytes的地址空间,但内存空间没有初始化和类型化
  2. 对内存空间进行类对象的初始化。调用构造函数,给private基本变量赋值,指针变量指向对应位置
  3. 返回对象指针

当我们用delete释放掉类对象的时候

delete pA;

背后完成的工作是:
在这里插入图片描述
delete的工作有以下几点:

  1. 调用指针所指向对象的析构函数,对打开的文件进行关闭
  2. 通过调用delete库函数来释放掉该对象的内存空间,传入的参数是指针pA,也就是对象的地址
1.2 用new type[]和delete []申请和释放数组

1.申请和释放基本数据类型的数组空间
在这里插入图片描述
在这里插入图片描述
这里会发现,创建数组和创建单个对象的不同,这里new 和 delete变成了:
type *name = new type[ ];
delete [] name;

在上面的例子中,释放string类型数组空间时实际上先为10个string对象分别调用析构函数,再释放掉为10个string对象所分配的所有内存空间;而释放int类型数组空间时,因为int是内置类型不存在析构函数,所以直接释放掉了为10个int类型变量分配的所有空间。

因此,非内置类型数据用new type[] 来动态分配内存时,必须保存数据的维度,以确定在析构时需要调用对象析构函数的次数。C++的做法是在分配数组空间时在前面多分配了4 Bytes 大小的空间,专门保存数组的维度,在delete的时候根据数据维度调用析构函数,最后再释放所有内存空间。

以创建pA类对象数组为例说明 Type *name = new Type[] 和 delete[] name的运行机制
首先为对象数组分配内存空间:

class A *pAa = new A[3];

背后的工作是:
在这里插入图片描述
当我们释放对象数组的内存空间时:

delete [] pAa;

背后的工作是:
在这里插入图片描述
正如前面所说:依次为数组中每个对象调用析构函数,调用析构函数的总次数是由调用new库函数时开辟的内存空间的前4 Bytes 中保存的数据决定的;调用delete[] name 库函数时,其参数不是指针name的值(也是第一个数组元素的地址),而是这个地址值减去4 Bytes

1.3 内存泄漏

在这里插入图片描述

2. malloc 和 free

  1. 头文件是#include<stdlib.h>,函数声明为:

void* malloc(size_t size);

  1. 参数size_t size表示动态内存分配空间的大小,以字节为单位。
  2. malloc()函数的返回值是一个指针,或者说是分配后内存空间的首地址.
  3. 如果malloc()函数申请空间成功则返回一段内存空间的首地址,失败则返回NULL
  4. 返回指针类型需要强制类型转换(有安全隐患)

int *p = (int *) malloc(sizeof(int));

  1. 在使用malloc()函数申请的空间之前,最好用memset()函数把这段内存空间清理一下。malloc智能保证内存空间的大小,无法保证是否有垃圾数据
  2. malloc和free要配对使用,否则会内存泄漏

案例:

//0.包含头文件<stdlib.h>
//1.定义一个char* 指针变量p,并分配10个字节内存空间(字符数组)
char *p = (char *)malloc(sizeof(char));

//2.将字符数组中的内容全部修改为0
memset(p, 0, 10 * sizeof(char));

//3.复制一段字符串到p指向的数组空间(长度要比所分配的内存小)
strcpy(p, "hello ");

//4.用realloc扩充p指向的内存空间
p = (char*)realloc(p, 20 * sizeof(char));

//4.在原字符串后面再拼接一段字符
strcat(p, "world");

//5.释放空间
free(p);


3.new/delete 和 malloc/free的区别

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
其他(与上文提到的有重复):

  1. new、delete是C++中的操作符(关键字),通过特定的语法可以组成表达式。malloc和free是标准库函数。
  2. malloc free是库函数,不是运算符,不在编译器控制范围之内,不能够自动调用构造函数和析构函数。mallloc只是为变量分配了内存,free只是释放变量的内存。
  3. new在为对象申请分配内存空间时,可以自动调用构造函数,同时也可以完成对对象的初始化。同理,delete也可以自动调用析构函数。
  4. new返回的是指定类型的指针,并且可以自动计算所申请内存的大小;malloc需要我们计算申请内存的大小,并且在返回时强行转换为实际类型的指针。
  5. new从自由存储区分配内存;malloc从堆上分配内存。
  6. 与malloc、free相比,new、delete不仅能动态分配内存空间,而且会调用构造函数、析构函数对对象进行初始化和销毁。

参考文献:
C/C++——C++中new与malloc的10点区别
C++读书笔记—malloc()函数的注意点及使用示例

猜你喜欢

转载自blog.csdn.net/weixin_40937100/article/details/88848886
今日推荐