C/C++内存管理(含C++中new和delete的使用)
1、C/C++内存分布
int globalVar = 1; static int staticGlobalVar = 1; int main() { static int staticVar = 1; int localVar = 1; int num1[10] = {1, 2, 3, 4}; char char2[] = "abcd"; const char *pChar3 = "abcd"; int *ptr1 = (int *) malloc(sizeof(int) * 4); int *ptr2 = (int *) calloc(4, sizeof(int)); int *ptr3 = (int *) realloc(ptr2, sizeof(int) * 4); free(ptr1); free(ptr3); return 0; } //1. 选择题: // 选项: A.栈 B.堆 C.数据段(静态区) D.代码段(常量区) // globalVar在哪里?____ staticGlobalVar在哪里?____ // staticVar在哪里?____ localVar在哪里?____ // num1 在哪里?____ // // char2在哪里?____ *char2在哪里?___ // pChar3在哪里?____ *pChar3在哪里?____ // ptr1在哪里?____ *ptr1在哪里?____ //2. 填空题: // sizeof(num1) = ____; //sizeof(char2) = ____; strlen(char2) = ____; // sizeof(pChar3) = ____; strlen(pChar3) = ____; // sizeof(ptr1) = ____; //3. sizeof 和 strlen 区别? //
- 说明:
2、C语言中动态内存管理方式:malloc/calloc/realloc/free
malloc
、calloc
和realloc
是在C语言中用于动态内存分配的三个函数,它们有一些区别,主要体现在它们的功能和用法上。
malloc(Memory Allocation,内存分配):
void* malloc(size_t size);
calloc(Contiguous Allocation,连续分配):
void* calloc(size_t num_elements, size_t element_size);
realloc
用于重新分配已分配内存的大小,可以用于扩大或缩小内存块的大小。- 如果原始内存块的地址不为空,
realloc
会尝试在原始地址上修改内存块的大小(如果新内存大小大于这块原始空间,则还是需要重新开辟内存),如果原始地址为空,则行为类似于malloc
。void* realloc(void* ptr, size_t new_size);
总结:
int main() { int *p1 = (int *) malloc(sizeof(int)); free(p1); // 1.malloc/calloc/realloc的区别是什么? int *p2 = (int *) calloc(4, sizeof(int)); int *p3 = (int *) realloc(p2, sizeof(int) * 10); // 这里需要free(p2)吗? --- 看情况 free(p3); return 0; }
3、C++动态内存管理
C语言内存管理方式在C++中可以继续使用,但有些地方就无能为力(比如给对象初始化),而且使用起来比较麻烦,因此C++又提出了自己的内存管理方式:通过new和delete操作符进行动态内存管理。
3.1、new/delete操作内置类型
int main() { // 动态申请一个int类型的空间 int *ptr4 = new int; // 动态申请一个int类型的空间并初始化为10 int *ptr5 = new int(10); cout << *ptr5 << endl; // 动态申请10个int类型的空间 int *ptr6 = new int[3]; // 动态申请10个int类型的空间并初始化前3个 int *ptr7 = new int[3]{1, 2, 3}; cout << ptr7[0] << ptr7[1] << ptr7[2] << ptr7[3]; delete ptr4; delete ptr5; delete[] ptr6; delete[] ptr7; }
3.2、new/delete操作自定义类型
class Date { public: Date() : _year(1), _month(1), _day(1) { cout << "Date()" << endl; } Date(int year, int month, int day) : _year(1), _month(1), _day(1) { _year = year; _month = month; _day = day; cout << "Date()" << endl; } ~Date() { cout << "~Date()" << endl; } private: int _year; int _month; int _day; }; int main() { Date *ptr1 = new Date(); Date *ptr2 = new Date(2, 2, 2); Date *ptr3 = new Date[10]{{1, 2, 2}}; free(ptr1); delete ptr2; delete[] ptr3; return 0; }
4、operator new与operator delete函数
new
和delete
是用户进行动态内存申请和释放的操作符,operator new
和operator delete
是系统提供的全局函数,new
在底层调用operator new
全局函数来申请空间,delete
在底层通过operator delete
全局函数来释放空间。
operator new
:该函数实际通过malloc
来申请空间,当malloc
申请空间成功时直接返回;申请空间失败,尝试执行空间不足应对措施,如果改应对措施用户设置了,则继续申请,否则抛异常。operator delete
最终是通过free
来释放空间的。class Date { public: Date() : _year(1), _month(1), _day(1) { cout << "Date()" << endl; } Date(int year, int month, int day) : _year(1), _month(1), _day(1) { _year = year; _month = month; _day = day; cout << "Date()" << endl; } ~Date() { cout << "~Date()" << endl; } private: int _year; int _month; int _day; }; int main() { //operator new -- 不调用构造函数 和 malloc 基本一样 Date *ptr6 = (Date *) operator new(sizeof(Date)); delete new(ptr6) Date; ptr6 = nullptr; return 0; }
5、new和delete的实现原理
5.1、内置类型
如果申请的是内置类型的空间,
new
和malloc
,delete
和free
基本类似,不同的地方是:new
/delete
申请和释放的是单个元素的空间,new[]
和delete[]
申请的是连续空间,而且new
在申请空间失败时会抛异常,malloc
会返回NULL
。
5.2、自定义类型
new
的原理
delete
的原理
new T[N]
的原理
delete[]
的原理这里我们需要注意一个现象:对于内置类型在
new T[N]
时候,往往开辟的内存空间会大于N*sizeof(T)
,可能会多出4
个字节。原本这里
ptr2
开辟的空间size应该是12*10 = 120
,但是这里显示124
,其中4
个字节是用来存储开辟连续Date
对象的个数。class Date { public: Date() : _year(1), _month(1), _day(1) { cout << "Date()" << endl; } Date(int year, int month, int day) : _year(1), _month(1), _day(1) { _year = year; _month = month; _day = day; cout << "Date()" << endl; } ~Date() { cout << "~Date()" << endl; } private: int _year; int _month; int _day; }; int main() { Date* ptr1 = new Date; delete ptr1; Date* ptr2 = new Date[10]; delete[] ptr2; return 0; }
但是如果是内置类型
new T[N]
,则不需要另外的空间存个数。原本这里
ptr3
开辟的空间size
应该是4*10 = 40
,并且这里显示40
,即没有开辟空间存个数。class Date { public: Date() : _year(1), _month(1), _day(1) { cout << "Date()" << endl; } Date(int year, int month, int day) : _year(1), _month(1), _day(1) { _year = year; _month = month; _day = day; cout << "Date()" << endl; } ~Date() { cout << "~Date()" << endl; } private: int _year; int _month; int _day; }; int main() { Date* ptr1 = new Date; delete ptr1; Date* ptr2 = new Date[10]; delete[] ptr2; int* ptr3 = new int[10]; delete[] ptr3; return 0; }
原因:这多出来的
4
个字节是用来记录开辟T
大小连续空间的个数,以便于delete []
进行析构和释放空间。这里如果不写析构函数(默认成员变量没有开辟空间,如果开辟了空间,必须调用析构函数释放空间,不然会内存泄露)的话就不报错,因为成员变量都是内置类型没有开空间,不需要调用析构函数,也就不需要在前面添加
4
字节存个数,即自定义类型new T[N]
可以直接delete
,内置类型也一样。class Date { public: Date() : _year(1), _month(1), _day(1) { cout << "Date()" << endl; } Date(int year, int month, int day) : _year(1), _month(1), _day(1) { // _a = new int[10]; _year = year; _month = month; _day = day; cout << "Date()" << endl; } // ~Date() { // cout << "~Date()" << endl; // } private: // int* _a; int _year; int _month; int _day; }; int main() { Date *ptr1 = new Date; delete ptr1; Date *ptr2 = new Date[10]; // 这里如果不写析构函数(默认成员变量没有开辟空间,如果开辟了空间,必须调用析构函数释放空间,不然会内存泄露)的话就不报错 // 因为成员变量都是内置类型没有开空间,不需要调用析构函数,也就不需要在前面添加4字节存个数 delete ptr2; return 0; }
6、定位new表达式(placement-new)
定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象。
class Date { public: Date() : _year(1), _month(1), _day(1) { cout << "Date()" << endl; } Date(int year, int month, int day) : _year(1), _month(1), _day(1) { _year = year; _month = month; _day = day; cout << "Date()" << endl; } ~Date() { cout << "~Date()" << endl; } private: int _year; int _month; int _day; }; int main() { Date *p = (Date *) operator new(sizeof(Date)); // 不能显式调用构造函数 // p->Date(); // 定位new可以显式调用构造函数 new(p)Date(1, 1, 1); p->~Date(); return 0; }
OKOK,C/C++内存管理就到这里。如果你对Linux和C++也感兴趣的话,可以看看我的主页哦。下面是我的github主页,里面记录了我的学习代码和leetcode的一些题的题解,有兴趣的可以看看。
原文地址:https://blog.csdn.net/qq_44121078/article/details/134697667
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_28906.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!