使用new运算符进行动态内存分配

  • 编译器使⽤三块独⽴的内存:⼀块⽤于 静态变量static(可能再细分),⼀块⽤于⾃动变量,另外⼀块⽤于动态存储new。
  • 动态内存由运算符new和delete控制
  • 将函数中局部(指针)变量的连接性声明为外部的extern,则文件中位于该声明后面的所有函数都可以使用该局部(指针)变量,例子:extern float* p_fees;
  1. 使用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;
      
  2. new失败时

    new可能找不到请求的内存量。在最初的10年中,C++在这种情况 下让new返回空指针,但现在将引发异常std::bad_alloc。

  3. 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));
      
  4. 定位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函数。

  5. 定位new的其他形式:

标准定位 new调⽤⼀个接收两个参数的new()函数:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i1Ue2CY1-1682827668216)(C:\Users\ALAN.XUAN\AppData\Roaming\Typora\typora-user-images\image-20211026034039430.png)]

定位new函数不可替换,但可重载。它⾄少需要接收两个参数,其 中第⼀个总是std::size_t,指定了请求的字节数。这样的重载函数都被称为定义new,即使额外的参数没有指定位置。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值