- 编译器使⽤三块独⽴的内存:⼀块⽤于 静态变量static(可能再细分),⼀块⽤于⾃动变量,另外⼀块⽤于动态存储new。
- 动态内存由运算符new和delete控制
- 将函数中局部(指针)变量的连接性声明为外部的extern,则文件中位于该声明后面的所有函数都可以使用该局部(指针)变量,例子:extern float* p_fees;
-
使用new运算符初始化
- 如果要为内置的标量类型(如int或double)分配存储空间并初始化,可在类型名后⾯加上初始值,并将其⽤括号括起:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l9uBLP7r-1682827668211)(C:\Users\ALAN.XUAN\AppData\Roaming\Typora\typora-user-images\image-20211026025034443.png)]
-
要初始化常规结构或数组,需要使⽤⼤括号的列表初始化, 这要求编译器⽀持C++11。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JDOjNVkL-1682827668213)(C:\Users\ALAN.XUAN\AppData\Roaming\Typora\typora-user-images\image-20211026025147544.png)]
-
可将列表初始化⽤于单值变量:
int *pin=new int {6}; //*pi set to 6; double *pdo=new double {99.99}; //*pd set to 99.99;
-
new失败时
new可能找不到请求的内存量。在最初的10年中,C++在这种情况 下让new返回空指针,但现在将引发异常std::bad_alloc。
-
new:运算符、函数和替换函数
-
运算符new和new []分别调⽤如下函数:
void* operator new(std::size_t); //new void* operator new[](std::size_t); //new[]
-
这些函数被称为分配函数(alloction function),它们位于全局名称空间中。同样,也有由delete和delete []调⽤的释放函数(deallocation function):
void* operator delete(std::size_t); //delete void* operator delete[](std::size_t); //delete[]
-
-
基本语句:
int* pi=new int;将被替换为
//1 int* pi=new int; //将被替换为 int* pi=new(sizeof(int)); //2 int* pa=new int[40]; //将被替换为 int* pa=new(40*sizeof(int));
-
-
定位new运算符
-
new负责在堆(heap)中找到一个足以能够满足要求的内存块。
-
定位new 运算符能够指定要使用的位置
-
可以使⽤这种特性来设置其内存管理规程、处理需要通过特定地址进⾏访问的硬件或在特定位置创建对象。
-
要使⽤定位new特性,⾸先需要包含头⽂件new,它提供了这种版本 的new运算符的原型;然后将new运算符⽤于提供了所需地址的参数。
-
使⽤定位new 运算符时,变量后⾯可以有⽅括号,也可以没有。
-
new的4种用法:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NYAYMVmz-1682827668214)(C:\Users\ALAN.XUAN\AppData\Roaming\Typora\typora-user-images\image-20211026031152962.png)]
出于简化的⽬的,这个⽰例使⽤两个静态数组来为定位new运算符提供内存空间。因此,上述代码从buffer1中分配空间给结构chaff,从 buffer2中分配空间给⼀个包含20个元素的int数组。
-
使⽤常 规new运算符和定位new运算符创建动态分配的数组。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0jdtMqS6-1682827668215)(C:\Users\ALAN.XUAN\AppData\Roaming\Typora\typora-user-images\image-20211026031700368.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mSJo2Zey-1682827668215)(C:\Users\ALAN.XUAN\AppData\Roaming\Typora\typora-user-images\image-20211026031746677.png)]
-
-
定位new运算符确实将 数组p2放在了数组buffer中,p2和buffer的地址都是00FD9138。然⽽,它 们的类型不同,p1是double指针,⽽buffer是char指针(顺便说⼀句,这 也是程序使⽤(void *)对buffer进⾏强制转换的原因,如果不这样做, cout将显⽰⼀个字符串)同时,常规new将数组p1放在很远的地⽅,其 地址为006E4AB0,位于动态管理的堆中。
-
第⼆个常规new运算符查找⼀个新的内存 块,其起始地址为006E4B68;但第⼆个定位new运算符分配与以前相同 的内存块:起始地址为00FD9138的内存块。定位new运算符使⽤传递给 它的地址,它不跟踪哪些内存单元已被使⽤,也不查找未使⽤的内存 块。这将⼀些内存管理的负担交给了程序员。
-
对于常规new运算符, 下⾯的语句释放起始地址为006E4AB0的内存块,因此接下来再次调⽤ new运算符时,该内存块是可⽤的:
delete [] pd1;
-
不能使⽤delete来释放使⽤定位new运 算符分配的内存。
-
事实上,在这个例⼦中不能这样做。buffer指定的内存是静态内存,⽽delete只能⽤于这样的指针:**指向常规new运算符分配的堆内存。**也就是说,数组buffer位于delete的管辖区域之外,
-
如果buffer是使⽤常规new运算符创建的,便可以使⽤常 规delete运算符来释放整个内存块。
-
定位new运算符的另⼀种⽤法是,将其与初始化结合使⽤,从⽽将 信息放在特定的硬件地址处。
-
-
定位new运算符的⼯作原理。基本上,它只是返回传递给它的地址,并将其强制转换为void *,以便能够赋给任何指针类 型。但这说的是默认定位new函数,C++允许程序员重载定位new函数。
-
-
定位new的其他形式:
标准定位 new调⽤⼀个接收两个参数的new()函数:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i1Ue2CY1-1682827668216)(C:\Users\ALAN.XUAN\AppData\Roaming\Typora\typora-user-images\image-20211026034039430.png)]
定位new函数不可替换,但可重载。它⾄少需要接收两个参数,其 中第⼀个总是std::size_t,指定了请求的字节数。这样的重载函数都被称为定义new,即使额外的参数没有指定位置。