(C++)动态内存管理

C语言动态内存管理:

malloc , calloc , realloc , free

malloc :只开辟空间
calloc :开辟空间+初始化
realloc :

①当ptr = NULL 时,= malloc
②扩容,堆上内存足够
③重新开辟空间,内存不够时开辟新的内存,且释放旧内存


C++动态内存管理

"C++"
>通过 new 和 delete 动态管理内存(不是函数,是操作符)
>通过 new 和 delete 动态管理对象
>通过 new[] 和 delete[] 动态管理对象数组

malloc , calloc , realloc 只开辟空间
new , delete 开空间,调构造(初始化),调析构(释放内存)

开辟内存举例:

void Test() {
    int* p1 = new int;//只开一个int的空间,里面保存随机值,不初始化
    int* p2 = new int(1);//开一个int的空间,并将值初始化为1
    int* p3 = new int[3];//开三个int的空间

    delete p4;
    delete p2;
    delete[] p3;
}

new,delete,delete[], 为【操作符】
int 为【类型】
(1),小圆括号内数值为【初始化】
[3],方括号内内容为【对象个数】

初始化举例:

int i = 10;// i = 10
i = int();//i = 0,因为全缺省构造(int i = 0)
i = int(20);//i = 20

new和delete也可以开辟类的空间:

class AA {
piblic:
    AA() {
    };
    ~AA() {
    };
}//空类大小为一个字节

int main() {
    AA* p1 = new AA;
    free(p1);//new开辟的空间一律使用delete释放内存,不可以使用free
    delete p1;
}

注意:malloc & free ; new & delete ; new[] & delete[] 一定要配合使用,不可以用错,否则可能出现内存泄漏甚至奔溃的问题!!!


new[]时底层处理的机制

动态申请内存库函数:

void* operator new (size_t size);
void operator delete (size_t size);

void* operator new[] (size_t size);
void operator delete[] (size_t size);

实际上:

  1. operator new/operator delete , operator new[]/operator delete[] 和 malloc/free用法一致;
  2. 他们只负责开辟/释放空间,不会调用构造函数/析构函数来初始化/清理对象;
  3. 且operator new 和 operator delete 只是 malloc 和 free 的一层封装。

举例:

AA* P1 = (AA*)operator new(4);//==malloc,不调构造和析构
operator delete(p1);

char* p2 = (char*) malloc (0x7fffffff);
printf("%p\n",p2);//必须使用printf,输出00000000(输出提示)

char* p3 = (char*)operator new(0x7fffffff);
printf("%p\n",p3);//抛异常

·new

1.调用operator new分配空间
2.调用构造函数初始化对象

·delete

1.调用析构函数清理对象
2.调用operator delete释放空间

new/delete 图解

·new[N]

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

·delete[]

1.调用N次析构函数清理对象(思考这里的N是怎么来的?)
2.调用operator delete释放空间

new[]/delete[] 图解

· 思考这里的N是怎么来的?
new[] 在申请内存时,会多申请4个字节,用来保存N,所以delete[]释放内存时也会向前读取四个字节,获取N的值,用来调析构函数

“`
class AA {
public:
AA() {
};
~AA() {
};
}

int main() {
AA* p1 = new AA;
delete[] p1;//奔溃,(越界)单个对象不会向前多开4个字节
free(p1);//不奔溃,(没调析构)可能会内存泄漏

AA* p2 = new AA[10];
free(p2);//奔溃,没调析构
delete p2;//奔溃,少调析构
//释放错位置,只传了p1,未向前偏移四个字节(内存,整取整还,不能从中间开始释放)

int* p3 = new int[10];
delete p2;//未多开4个字节,不需要调用析构,不奔溃,编译器识别到int的析构函数没有做什么操作,所以不用调

结论:
严格来讲,new[]一定要多开4个字节,记录N的值,编译器识别析构函数可调可不调时,则不多开字节(自己写的析构,一定调;编译器默认生成,会优化,查看有无调用必要)
有无必要调用析构,决定是否多开四个字节


new/delete和malloc/free的区别

1.他们都是动态内存管理的入口;
2.malloc/free 是C/C++标准库的函数,new/delete 是 C++操作符;
3.malloc/free知识动态分配内存空间/释放空间,而new/delete除了分配空间还会调用构造函数和析构函数进行初始化与清理;
4.malloc/free需要动手计算类型大小且返回值是 void* ,new/delete可以自己计算类型的大小,且返回值是对应类型的指针;
5.malloc失败后return 0 , new失败后抛异常

猜你喜欢

转载自blog.csdn.net/giraffe_255/article/details/79906050