【C++】内存的存储方案与动态分配new的讲解
目录
1. 基本知识
什么是动态内存?
使用new和delete(C语言中使用函数malloc( ))分配的内存,我们叫做动态内存。动态内存由new和delete控制,不像前述的变量内存分配是由作用域和链接性规则决定,而动态内存分配取决于new和delete何时被使用。
编译器分配3种内存:
一块用于静态变量(可能再细分),一块用于自动变量,一块用于动态存储。
2. new 运算符
2.1 使用new运算符时的初始化
如何初始化动态分配的变量:
- c++98中:为内置类型(double,int等)分配存储空间并初始化,可以在类型名后面加上用括号括起来的初始值。例如:
-
int * pt=new int (6);
-
double * pc=new double (0.32);
- c++11中:既支持c++98方式的初始化,新增对结构或数组的初始化,常使用大括号的列表初始化 。还支持将列表初始化用于单值变量。例如:
-
struct student
-
{
-
char name[20];
-
int class;
-
}
-
-
student * one=new student {"Mary",2}; //new初始化结构
-
-
int * pm=new int[4]{2,4,6,8}; //new初始化数组
-
-
int * ps=new int {4};
2.2 new失败时如何处理?
new可能找不到请求的内存量。在最初的10年间,c++在这种情况下让new返回空指针,但现在将引发异常 std:bad_alloc。
2.3. new:运算符,函数和替换函数
new运算符分配动态内存时,运算符 new 和 new [ ] 分别调用如下函数:
-
void* operator new (std::size_t); //使用new
-
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 相同。
示例程序
-
#include <iostream>
-
#include <new>
-
using namespace std;
-
....
-
char buffer[50];
-
-
int main()
-
{
-
int* p1=new int (4);//常规new
-
int* p2=new int [4];//常规new数组
-
int* p3=new (buffer) int;//定位new,从buffer数组开始地址处分配1个int内存
-
int* p4=new (buffer +sizeof(int)) int [4];//定位new,从buffer数组偏移sizeof(int)量的地址处开始分配4个int内存
-
-
.....
-
-
return 0;
-
}
如下程序演示了定位new 和常规 new的使用:分别使用常规new和定位new创建
-
#include <iostream>
-
#include <new>
-
using namespace std;
-
const int N = 4;
-
const int BUFF = 512;
-
char buffer[BUFF];
-
-
int main()
-
{
-
/************************************************************************/
-
double* p1 = new double[N];
-
double* p2 = new (buffer) double[N];
-
for (int i = 0; i<N; i++)
-
{
-
p1[i] = p2[i] = 1000 + 30 * i;
-
}
-
cout << "常规 new 和 定位 new :\n";
-
cout << "内存地址 :\n";
-
cout << "堆开始地址 :" << p1 << " 静态数组buffer内存区开始地址 :" << p2 << endl;
-
cout << "内存区内容 :\n";
-
for (int i = 0; i<N; i++)
-
{
-
cout << p1[i] << " at " << &p1[i] << " ; " << p2[i] << " at " << &p2[i] << "\n";
-
}
-
/************************************************************************/
-
double* p3 = new double[N];
-
double* p4 = new (buffer) double[N];
-
for (int i = 0; i<N; i++)
-
{
-
p3[i] = p4[i] = 1000 + 60 * i;
-
}
-
cout << "常规 new 和 定位 new :\n";
-
cout << "内存区内容 :\n";
-
for (int i = 0; i<N; i++)
-
{
-
cout << p3[i] << " at " << &p3[i] << " ; " << p4[i] << " at " << &p4[i] << "\n";
-
}
-
/************************************************************************/
-
delete[] p1;
-
p1 = new double[N];
-
p2 = new (buffer + N*sizeof(double)) double[N];
-
for (int i = 0; i<N; i++)
-
{
-
p1[i] = p2[i] = 1000 + 80 * i;
-
}
-
cout << "常规 new 和 定位 new :\n";
-
cout << "内存区内容 :\n";
-
for (int i = 0; i<N; i++)
-
{
-
cout << p1[i] << " at " << &p1[i] << " ; " << p2[i] << " at " << &p2[i] << "\n";
-
}
-
-
delete[] p1;
-
delete[] p3;
-
-
return 0;
-
}
程序分析:
- 定位 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
- 点赞
- 收藏
- 关注作者
评论(0)