new与malloc

基本概念

【c】malloc/free从堆中分配/释放内存(malloc=memory allocation,malloc和free是函数)

//标准
void *malloc(int NumBytes); //NumBytes为要分配的字节数
void *free(void *FirstByte);
//例
int *p = (int *)malloc(sizeof(4));
free(p);

【c++】new/delete从堆中分配/释放内存(new和delete是运算符或标识符)

//指针变量名 = new 类型标识符;
int *p1 = new int;
//指针变量名 = new 类型标识符(初始值);
int *p2 = new int(0);
//指针变量名 = new 类型标识符[内存单元个数];
int *p3 = new int[3];
 
//释放
delete p1;
delete p2;
delete[] p3;

【注意】

(1)delete后,指针指向的地址不变,指向的内容里的东西没有了!

(2)new成功一定要delete!

(3)不能重复调用delete!

(4)能用nullptr的地方不用null!

 

细说

1、new、delete(关键字或运算符)同sizeof一样不是函数,与malloc和free相比多调用构造和析构函数

2、new的时候干了两件事:先分配内存(用operator new() 函数),再调用构造函数来初始化内存

      delete的时候干了两件事:先调用析构函数,再释放内存(用operator delete() 函数)

3、基本new如何记录分配的内存大小供delete使用(不同编译器不同):new内部会记录字节数

4、申请、释放一个数组

A *pA = new A[2]();    //泄露6字节而不是2字节,多的4字节用来记录new了几个类类型

 

详谈

1、new时加不加括号区别

int *p1 = new int;    //初值随机
int *p2 = new int();    //初值给0

2、new对象时加括号与否的区别

int *p1 = new A;
int *p2 = new A();

1)若类A为空类:没有区别

2)若类A中有成员变量:带括号的初始化会把一些和成员变量有关的内存请零(不是全部)

3)若类A中有构造函数:m_i等成员变量的问题就交给构造函数了,带不带括号的效果一样

3、new和delete具体都干了啥(再说一遍)(测试方法:调试——窗口——反汇编)

new首先调用了operator new函数,这个函数中调用了malloc函数,然后调用了A::A()构造函数;

delete首先调用了A::~A()析构函数,然后调用了operator delete函数,这个函数中调用了free函数。

注:malloc和free这一层再往下走就不是跨平台的了。

 

new与malloc的区别

1、new分配内存按照数据类型进行分配,malloc分配内存按照大小分配;

2、new不仅分配一段内存,而且会调用构造函数,但是malloc则不会;同理,delete销毁的时候会调用对象的析构函数,而free则不会;

3、new返回的是指定对象的指针,而malloc返回的是void*,因此malloc的返回值一般都需要进行类型转化;

4、new是一个操作符可以重载,malloc是一个库函数;

5、new分配的内存要用delete销毁,malloc要用free来销毁;

6、malloc分配的内存不够的时候,可以用realloc扩容,new没有这样的操作。

【realloc原理】

realloc是从堆上分配内存的,当扩大一块内存空间时,realloc()试图直接从堆上现存的数据后面的那些字节中获得附加的字节,如果能够满足,自然天下太平;如果数据后面的字节不够,那么就使用堆上第一个有足够大小的自由块,现存的数据然后就被拷贝至新的位置,而老块则放回到堆上,这句话传递的一个重要的信息就是数据可能被移动。

int len = 7;
int *a = (int*)malloc(sizeof(int)*len);
a[1] = 256;
a[2] = 5;
len++;
int* aold = a;
a = (int*)realloc(a,sizeof(int)*len);

前面两句定义了1个长度为7的int型数组,每个元素的字节长度是4,所以共占 28byte 内存;

最后一句:

1)假如数组 a 内存里接着的4个字节还没被其他对象或程序占用,那么就直接把后面4个字节加给数组a,数组前面7个旧的元素的值不变,  数组a的头部地址也不变;

2)假如数组 a 内存里接着的4个字节已经被占用了,那么realloc函数会在内存其他地方找1个连续的 32byte 内存空间,把数组a的7个旧元素的值搬过去,所以数组a的7个旧元素的值也不变,但是数组a的头部地址变化了。但是这时我们无需手动把旧的内存空间释放,因为realloc函数改变地址后会自动释放旧的内存,再手动释放程序就会出错了。

7、new如果分配失败了会抛出bad_alloc的异常,而malloc失败了会返回NULL。

因此对于new,正确的姿势是采用try...catch语法,而malloc则应该判断指针的返回值。为了兼容很多c程序员的习惯,C++也可以采用new(nothrow)的方法禁止抛出异常而返回NULL。

#include<new>    //必须使用new头文件
Manager * pManager = new (nothrow) Manager();
if(pManager == NULL)
{
    //记录日志
    return false;
}

 

知识补充:try-catch用法

例1:数组越界

#include<iostream>
using namespace std;
enum index{underflow, overflow};
int array_index(int *A, int n, int index);
int main()
{
    int *A = new int[10];
    for(int i=0; i<10; i++)
        A[i] = i;
    try
    {
        cout<<array_index(A,10,5)<<endl;
        cout<<array_index(A,10,-1)<<endl;
        cout<<array_index(A,10,15)<<endl;
    }
    catch(index e)
    {
        if(e == underflow)
        {
            cout<<"index underflow!"<<endl;
            exit(-1);
        }
        if(e == overflow)
        {
            cout<<"index overflow!"<<endl;
            exit(-1);
        }
    }
    return 0;
}
int array_index(int *A, int n, int index)
{
    if(index < 0) throw underflow;
    if(index > n-1) throw overflow;
    return A[index];
}

例2:new失败bad_alloc

int * p;
try
{
    p = new int[10];
}
catch(bad_alloc)
{
    cerr<<"allocate failure!"<<endl;
    exit(-1);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值