【C++】内存的存储方案与动态分配new的讲解

举报
王博Kings 发表于 2020/12/30 00:00:17 2020/12/30
【摘要】 目录 1. 基本知识 什么是动态内存? 编译器分配3种内存: 2. new 运算符 2.1 使用new运算符时的初始化 2.2 new失败时如何处理? 2.3. new:运算符,函数和替换函数 2.4. 定位运算符new 示例程序 1. 基本知识 什么是动态内存? 使用new和delete(C语言中使用函数malloc( ))分配的内存,我们叫...

目录

1. 基本知识

什么是动态内存?

编译器分配3种内存:

2. new 运算符

2.1 使用new运算符时的初始化

2.2 new失败时如何处理?

2.3. new:运算符,函数和替换函数

2.4. 定位运算符new

示例程序


1. 基本知识

什么是动态内存?

使用new和delete(C语言中使用函数malloc( ))分配的内存,我们叫做动态内存。动态内存由new和delete控制,不像前述的变量内存分配是由作用域和链接性规则决定,而动态内存分配取决于new和delete何时被使用。

编译器分配3种内存:

一块用于静态变量(可能再细分),一块用于自动变量,一块用于动态存储。

2. new 运算符

2.1 使用new运算符时的初始化

如何初始化动态分配的变量:

  • c++98中:为内置类型(double,int等)分配存储空间并初始化,可以在类型名后面加上用括号括起来的初始值。例如:

  
  1. int * pt=new int (6);
  2. double * pc=new double (0.32);
  • c++11中:既支持c++98方式的初始化,新增对结构或数组的初始化,常使用大括号的列表初始化 。还支持将列表初始化用于单值变量。例如:

  
  1. struct student
  2. {
  3. char name[20];
  4. int class;
  5. }
  6. student * one=new student {"Mary",2}; //new初始化结构
  7. int * pm=new int[4]{2,4,6,8}; //new初始化数组
  8. int * ps=new int {4};

2.2 new失败时如何处理?

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

2.3. new:运算符,函数和替换函数

new运算符分配动态内存时,运算符 new 和 new [ ] 分别调用如下函数:


  
  1. void* operator new (std::size_t); //使用new
  2. void* operator new [] (std::size_t); //使用new[]

这些函数叫做 分配函数 。位于名称空间内,同样地,在使用 delete 和 delete[] 运算符时,也会调用类似函数。此处 size_t 是一个typedef,对应于合适的整形。 
例如,对于定义一个int分配内存时:基本语句

int* ps=new int {4};
 

调用函数,将会被转换为如下:

int* ps=new int(sizeof(int));
 

而数组分配内存时:

int* ph=new int [5];
 

调用new[] ,会被转换为:

int* ps=new int(5*sizeof(int));
 

2.4. 定位运算符new

new运算符在以上基础之上,还有另一个变体。被称为new定位运算符,它能够让使用者指定要使用的内存地址。因此可以使用new来设置其内存管理规程,处理需要通过特定地址进行访问的硬件或在特定位置创建对象。

定位new运算符使用:

  • 包含头文件 new ,它提供了 new 运算符的原型;
  • 然后将 new 运算符用于已经提供了的地址的参数;
  • 其它句法与常规new 相同。

示例程序


  
  1. #include <iostream>
  2. #include <new>
  3. using namespace std;
  4. ....
  5. char buffer[50];
  6. int main()
  7. {
  8. int* p1=new int (4);//常规new
  9. int* p2=new int [4];//常规new数组
  10. int* p3=new (buffer) int;//定位new,从buffer数组开始地址处分配1个int内存
  11. int* p4=new (buffer +sizeof(int)) int [4];//定位new,从buffer数组偏移sizeof(int)量的地址处开始分配4个int内存
  12. .....
  13. return 0;
  14. }

如下程序演示了定位new 和常规 new的使用:分别使用常规new和定位new创建


  
  1. #include <iostream>
  2. #include <new>
  3. using namespace std;
  4. const int N = 4;
  5. const int BUFF = 512;
  6. char buffer[BUFF];
  7. int main()
  8. {
  9. /************************************************************************/
  10. double* p1 = new double[N];
  11. double* p2 = new (buffer) double[N];
  12. for (int i = 0; i<N; i++)
  13. {
  14. p1[i] = p2[i] = 1000 + 30 * i;
  15. }
  16. cout << "常规 new 和 定位 new :\n";
  17. cout << "内存地址 :\n";
  18. cout << "堆开始地址 :" << p1 << " 静态数组buffer内存区开始地址 :" << p2 << endl;
  19. cout << "内存区内容 :\n";
  20. for (int i = 0; i<N; i++)
  21. {
  22. cout << p1[i] << " at " << &p1[i] << " ; " << p2[i] << " at " << &p2[i] << "\n";
  23. }
  24. /************************************************************************/
  25. double* p3 = new double[N];
  26. double* p4 = new (buffer) double[N];
  27. for (int i = 0; i<N; i++)
  28. {
  29. p3[i] = p4[i] = 1000 + 60 * i;
  30. }
  31. cout << "常规 new 和 定位 new :\n";
  32. cout << "内存区内容 :\n";
  33. for (int i = 0; i<N; i++)
  34. {
  35. cout << p3[i] << " at " << &p3[i] << " ; " << p4[i] << " at " << &p4[i] << "\n";
  36. }
  37. /************************************************************************/
  38. delete[] p1;
  39. p1 = new double[N];
  40. p2 = new (buffer + N*sizeof(double)) double[N];
  41. for (int i = 0; i<N; i++)
  42. {
  43. p1[i] = p2[i] = 1000 + 80 * i;
  44. }
  45. cout << "常规 new 和 定位 new :\n";
  46. cout << "内存区内容 :\n";
  47. for (int i = 0; i<N; i++)
  48. {
  49. cout << p1[i] << " at " << &p1[i] << " ; " << p2[i] << " at " << &p2[i] << "\n";
  50. }
  51. delete[] p1;
  52. delete[] p3;
  53. return 0;
  54. }

 

程序分析:

  • 定位 new 运算符将 p2 (p4)放在了数组 buffer 中,p2( p4 )和buffer数组地址相同;
  • 常规 new 运算符p3将查找一块新的内存块,起始地址与 p1 的不同;
  • 定位 new 运算符 p2 被重新分配,在buffer数组加上偏移量N*sizeof(double)的地址处;
  • 常规 new 运算符必须使用 delete[ ] 来释放,而定位 new 不使用 delete 释放,否则会出错误。

文章来源: kings.blog.csdn.net,作者:人工智能博士,版权归原作者所有,如需转载,请联系作者。

原文链接:kings.blog.csdn.net/article/details/96483145

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。