C++内存管理 - new/delete

new

在C语言中用于空间开辟的函数有: malloc, realloc, calloc.

在C++中则是使用new来开辟空间的.

new的使用

1. 为内置类型开辟空间

int* arr = new int[100];
// arr: 接收开辟好的空间的地址
// int: 开辟的空间是 int 类型的
// [100]: 代表开辟 100 个对应类型的空间
// 即 100 个 int 类型的空间: 100 * 4 = 400 字节

2. 为自定义类型开辟空间

class A
{
public:
    A(int a = 0);
    :_a(a)
    {}
private:
    int _a;
}

int main()
{
    A* pa = new A(10);
    // 为类型 A 实例化出一个对象, 并将对象中的 _a 初始化为10, 返回对象的地址
    return 0;
}

3. 为多个自定义类型开辟空间

class A
{
public:
    A(int a = 0);
    :_a(a)
    {}
private:
    int _a;
}

int main()
{
    A* p = new A[5]{1, 2, 3};
    // 创建了 5 个 A 类型对象, 前三个初始化为 1, 2, 3 后两个默认初始化为0
    return 0;
}

 new特性

1. new 对于内置类型没有什么区别

2. 对于自定义类型来说: 

   new 在创建对象时

   会通过调用自定义类型的构造函数来初始化对象

   而 malloc 或其他函数则不会, 只是单纯开辟出空间

delete

delete 则是用来代替C语言中的 free 函数.

delete 用来销毁开辟的空间, 回收空间资源.

delete的使用

1. 销毁内置类型

int* p = new int(10);
delete p;

对于单个对象, 使用 delete 进行空间销毁.
多个对象, 则需要使用 delete[] 来进行空间销毁.

int* p = new int[100];
delete[] p;

当使用 new 开辟了多个空间时 (new type[])

delete 也需要加上 [] 来释放空间 (delete []);

2. 销毁自定义类型

class A
{
public:
    A(int a = 0)
    :_a(a)
    {}

    ~A()
    {}
private:
    int _a;
}

int main()
{
    A* p = new A[10];
    A* tem = new A();
    delete tem;
    delete[] p;
    return 0;
}

使用方法和内置类型没有什么区别.

delete特性

1. 内置类型: delete 和 free 没有什么区别

2. 自定义类型: delete 会去调用对象的析构函数, free 则不会

3. 当面对多个空间时, delete 需要加上 [] (delete [])

 对于自定义类型还是使用 delete 来销毁, 否者可能造成内存泄漏.

class A
{
public:
    A(int size = 10)
    {
        arr = new int[size];
    }

    ~A()
    {
        delete[] arr;
    }
private:
    int* arr;
}

在上面的这个类中, 如果没有调用析构函数, 那么 arr 就没有被释放, 就造成了内存泄漏.
使用 free 只是释放了 arr 这个变量的空间, arr 所指向的空间并没有释放.

operator new 函数

new 的底层通过调用 operator new 函数来开辟空间.

operator new: 

虽然由 operator 关键字, 但是这里并不是运算符重载, 在这里, operator 就是一个名词

operator new 函数源码:

void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
void *p;
while ((p = malloc(size)) == 0)
	if (_callnewh(size) == 0)
	{
	    // 如果申请内存失败了,这里会抛出bad_alloc 类型异常
	    static const std::bad_alloc nomem;
	    _RAISE(nomem);
	}
return (p);
}

通过观察上面的源码可以看到:

new 底层还是通过 malloc 来开辟空间的.

使用 new 来开辟空间, 开辟成功, 返回指向此空间的指针, 失败则抛出异常.

operator delete 函数

同样 delete 底层也是通过调用 operator delete 函数来释放空间的.

operator delete 源码:

#define free(p) _free_dbg(p, _NORMAL_BLOCK)
void operator delete(void *pUserData)
{
     _CrtMemBlockHeader * pHead;
     RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));
     if (pUserData == NULL)
         return;
     _mlock(_HEAP_LOCK);
     __TRY
         pHead = pHdr(pUserData);
         _ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
         _free_dbg( pUserData, pHead->nBlockUse );
     __FINALLY
         _munlock(_HEAP_LOCK);
     __END_TRY_FINALLY
     return;
}

可以观察到: 

delete 调用了 _free_dbg(p, _NORMAL_BLOCK) 来释放空间.

_free_dbg(p, _NORMAL_BLOCK) 实际上就是 free(p)

 所以 delete 底层也是听过 free 来实现空间的释放的.

new创建对象的过程

对于内置类型 new 和 malloc 没有什么区别.

以下都针对于自定义类型

new

1. 调用 operator new 函数申请空间

2. 在申请空间之后, 调用对应的构造函数完成对象的构造

new type[n]

1. 调用 operator new[] 函数申请n份空间

2. 在申请空间之后, 调用 n次 对应的构造函数完成对象的构造

delete销毁对象的过程

对于内置类型 delete 和 free没有什么区别.

以下都针对于自定义类型

delete

1. 在空间上执行析构函数完成对象中资源的清理工作

2. 调用operator delete函数释放对象的空间

delete []

1. 在空间上 n次 执行析构函数完成对象中资源的清理工作

2. 调用 n次 operator delete函数释放对象的空间

new/delete 和 malloc/free区别

  1. malloc和free是函数,new和delete是操作符
  2. malloc申请的空间不会初始化,new可以初始化
  3. malloc申请空间时,需要手动计算空间大小并传递,new只需在其后跟上空间的类型即可,如果是多个对象,[]中指定对象个数即可
  4. malloc的返回值为void, 在使用时必须强转,new不需要,因为new后跟的是空间的类型*
  5. malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要,但是new需要捕获异常
  6. 申请自定义类型对象时,malloc/free只会开辟空间,不会调用构造函数与析构函数,而new在申请空间后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值