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 后两个默认初始化为0return 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);__TRYpHead = pHdr(pUserData);_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));_free_dbg( pUserData, pHead->nBlockUse );__FINALLY_munlock(_HEAP_LOCK);__END_TRY_FINALLYreturn;
}
可以观察到:
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区别
- malloc和free是函数,new和delete是操作符
- malloc申请的空间不会初始化,new可以初始化
- malloc申请空间时,需要手动计算空间大小并传递,new只需在其后跟上空间的类型即可,如果是多个对象,[]中指定对象个数即可
- malloc的返回值为void, 在使用时必须强转,new不需要,因为new后跟的是空间的类型*
- malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要,但是new需要捕获异常
- 申请自定义类型对象时,malloc/free只会开辟空间,不会调用构造函数与析构函数,而new在申请空间后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理