目录
一.C/C++内存分布
二.C语言动态内存管理
三.C++动态内存管理
new/delete操作符
operator new与operator delete
new/delete实现原理
定位new表达式(new-placement)
一.C/C++内存分布
栈(堆栈):存储非静态局部变量 ,函数参数,函数返回值等等(向下增长)。
内存映射段(不作讲解)
堆:程序运行时的动态内存分配(向下增长)。
数据段:存储全局变量和静态变量。
代码段:存储可执行代码和只读常量。
题目(巩固):
int globalVar = 1;
static int staticGlobalVar = 1;
void Test()
{
static int staticVar = 1;
int localVar = 1;
int num1[10] = {1, 2, 3, 4};
char char2[] = "abcd";
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);
}
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) = ____;
答案:
1. 选择题:
选项: A.栈 B.堆 C.数据段(静态区) D.代码段(常量区)
globalVar在哪里?__数据段__ staticGlobalVar在哪里?__数据段__
staticVar在哪里?__数据段__ localVar在哪里?__栈__
num1 在哪里?__栈__
char2在哪里?__栈__ *char2在哪里?__栈(a)__
pChar3在哪里?__栈__ *pChar3在哪里?__代码段(a)__
ptr1在哪里?__栈__ *ptr1在哪里?__堆__
2. 填空题:
sizeof(num1) = __40__;
sizeof(char2) = __5(隐藏的\0)__; strlen(char2) = __4__;
sizeof(pChar3) = __4/8__; strlen(pChar3) = __4__;
sizeof(ptr1) = __4/8__;
二.C语言动态内存管理
C语言动态内存管理主要通过使用以下函数:
malloc calloc realloc free
malloc函数原型:
void* malloc(size_t num);
功能:malloc以字节为单位开辟空间,开辟的空间不进行初始化,存储的是随机值。
calloc函数原型:
void* calloc(size_t num, size_t size);
功能:calloc开辟的空间大小为num*size字节,开辟的空间内容全部初始化为0。
realloc函数原型:
void* realloc(void* ptr, size_t num);
功能:realloc函数用于对已存在的动态开辟空间进行扩容,如果ptr位置传参为NULL,就与malloc别无二致。
realloc扩容的两种情况:
原地扩容:原空间后直接追加空间,原有的数据不发生改变。
异地扩容:原有的空间后没有足够多的空间,在堆空间上额外找一块新的连续的空间,原有的数据拷贝到这块新空间中,返回新空间的地址。
free函数原型:
void free(void* ptr);
功能:free函数用释放动态申请的空间,接收一个动态申请出来的空间的指针。给出来的指针必须是动态申请的完整空间。
三.C++动态内存管理
new/delete操作符
C++主要通过new和delete两个操作符进行动态内存管理。
语法:
new操作符
申请单个T类型对象的空间:new T,可在T后用()初始化对象。
申请多个T类型对象的空间:new T[N] —— N为要申请的对象个数;
可在T[N]后用{ }初始化对象。
delete操作符
释放单个对象的空间:delete 动态开辟空间的指针
释放多个对象的空间:delete[] 动态开辟空间的指针
总结:申请和释放单个对象的空间,用new和delete;申请和释放多个对象的连续空间,用new[] 和 delete[]。注意要配对使用。
例子:
new/delete操作内置类型:
void Test()
{// 动态申请一个int类型的空间int* ptr1 = new int;// 动态申请一个int类型的空间并初始化为10int* ptr2 = new int(10);// 动态申请3个int类型的空间int* ptr3 = new int[3];// 动态申请3个int类型的空间并初始化为1,2,3int* ptr4 = new int[3]{1,2,3};delete ptr1;delete ptr2;delete[] ptr3;delete[] ptr4;
}
new/delete操作自定义类型:
class A
{
public:A(int i = 1):_a(i){}
private:int _a;
};int main()
{//动态申请1个A类型的空间,自动调用默认构造A* ptr1 = new A;//动态申请1个A类型的空间,手动初始化//(隐式类型转换:先用10构造一个A类型临时对象,再用临时对象拷贝构造;编译器可能优化为直接构造)A* ptr2 = new A(10);//动态申请3个A类型的空间,自动调用3次默认构造A* ptr3 = new A[3];//动态申请3个A类型的空间,手动初始化(隐式类型转换,同上)A* ptr4 = new A[3]{ 1,2,3 };delete ptr1;delete ptr2;delete[] ptr3;delete[] ptr4;return 0;
}
new/delete和malloc/free最大的区别:对于自定义类型,new会自动调用默认构造,delete会自动调用析构函数;malloc/free函数则不会。
operator new与operator delete
operator new和oprator delete是系统提供的全局函数。new底层调用的是operator new全局函数,delete底层调用的是operator delete全局函数。
operator new全局函数,最终是通过malloc函数来申请空间的。不同的是,若空间申请失败,malloc函数返回空指针,而operator new函数会抛出异常。可以理解为,operator new全局函数是malloc函数的加强版,空间申请失败不再返回空指针,而是抛异常。
operator delete全局函数 ,最终是通过free函数来释放空间的。
new/delete实现原理
对于内置类型,new/delete与malloc/free几乎没有区别 。
对于自定义类型:
1.单对象new T/delete 指针
new T的原理:
1.调用opeartor new函数申请空间
2.在申请的空间上执行构造函数初始化对象
delete 指针 的原理:
1.调用析构函数,完成对象中资源的清理工作
2.调用operaotr delete函数释放空间
2.多对象new T[N] / delete[] 指针
new T[N]的原理:
1.调用operator new[]函数申请空间,在operator new[]函数中,实际是调用operator new函数完成对N个对象空间的申请。
2.在申请的空间上执行N次构造函数初始化N个对象
delete[] 指针 的原理:
1.调用N次析构函数,完成N个对象中资源的清理工作
2.调用operator delete[]函数,实际是调用operator delete函数完成N个对象空间的释放。
定位new表达式(new-placement)
用途/场景:用于已分配的原始空间中调用构造函数初始化对象。比如,内存池中申请的空间是不进行初始化的,如果申请的是自定义类型,需要使用定位new表达式显示调用构造函数初始化对象。
格式:new(place_address) Type 或 new(place_address) Type(initializer-list)。
place_address为指针变量,initializer-list为类型的初始化列表(或理解为调用构造函数的参数列表)。
代码示例:
//定位new表达式
class A
{
public:A(int i = 1):_a(i){}~A(){;}private:int _a;
};
int main()
{A* ptr = (A*)operator new(sizeof(A));//new(ptr) A;//显示调用默认构造new(ptr) A(10);//显示调用默认构造ptr->~A();//显示调用析构函数operator delete(ptr);ptr = nullptr;return 0;
}
文章的内容就到这里啦,希望大家多多点赞支持,谢谢大家!