动态分配和存储方案

使用new和delete(C语言中使用函数malloc( ))分配的内存,我们叫做动态内存。动态内存由new和delete控制,不像前述的变量内存分配是由作用域和链接性规则决定,而动态内存分配取决于new和delete何时被使用。通常,编译器分配3种内存:一块用于静态变量(可能再细分),一块用于自动变量,一块用于动态存储。

new运算符

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. new失败时

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

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));
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 释放,否则会出错误。
5. 定位运算符 new 函数

与常规 new 运算符一样,定位 new 也会调用函数 ,标准 定位 new 调用一个接收 2个参数的 new ( ) 函数:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值