全文目录
malloc() /free()
提到 new/delete 运算符 就不得不说 malloc() /free() 函数,C++是在C的基础上扩展的,所以我们先了解malloc() /free() 函数这一对函数的作用有助于更多的了解 new/delete 运算符。
原型解析
malloc() /free() 函数是C运行时库(CRT)的内置函数,其函数原型分别为:
// 摘选自内置 corecrt_malloc.h 头文件
_Check_return_ _Ret_maybenull_ _Post_writable_byte_size_(_Size)
_ACRTIMP _CRTALLOCATOR _CRT_JIT_INTRINSIC _CRTRESTRICT _CRT_HYBRIDPATCHABLE
void* __cdecl malloc(
_In_ _CRT_GUARDOVERFLOW size_t _Size
);
// 摘选自内置 corecrt_malloc.h 头文件
_ACRTIMP _CRT_HYBRIDPATCHABLE
void __cdecl free(
_Pre_maybenull_ _Post_invalid_ void* _Block
);
其中 Check_return Ret_maybenull Post_writable_byte_size(_Size)
_ACRTIMP _CRTALLOCATOR _CRT_JIT_INTRINSIC _CRTRESTRICT _CRT_HYBRIDPATCHABLE 这一部分的内容大致意思就是指明 malloc函数必须有返回,且有内存对齐要求, 按字节分配内存空间。
这也是 malloc() 函数的构成细节:
(1) malloc() 函数会指向已分配空间的void指针,如果可用内存不足,则返回null ;
(2) malloc() 函数至少分配 Size 大小的内存空间,可能因为内存对齐会导致分配比Size大的内存空间;
(3) 如果Size为0,malloc() 函数也会在堆内存中分配零长度的项并返回指向改项的指针,即使请求的内存较小也会检查malloc() 函数的返回值;
__cdecl 是C/C++ 默认的调用规范,表明函数参数是从右往左依次压入栈。还有__stdcall、_thiscall、__fastcall,读者可自行了解函数原型中调用规范的作用。
free() 函数用来释放由 malloc() 函数分配的内存块。
简化版本
一般讨论时我们只需关注两者的简化版本,即:
void* __cdecl malloc(
size_t _Size
);
void __cdecl free(
void* _Block
);
用法举例
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>
int main()
{
char* pChar = (char*)malloc(1024);
if (nullptr == pChar)
{
std::cout << "分配失败!\n";
}
std::cout << "分配成功!\n";
free(pChar);
pChar = nullptr;
std::cout << "释放成功!\n";
}
/*
* (以下是输出部分)
* 分配成功!
* 释放成功!
*/
new/delete
通过上面知道了 malloc()/ free() 函数其实是用来 分配/释放内存块的,仅此而已。既然已经有了分配/释放内存空间的函数了,那C++ 为什么还需要重载new和delete呢?那是因为对于非内部数据类型(自定义类就是其中之一)无法满足动态对象的创建和释放,因为动态对象的创建/释放需要自动调用构造函数/析构函数来完成, 不能把这个任务强加给已有malloc()和free(),这就是为什么要重载new/delete来动态构建对象的原因。
静态/动态类型
那么问题来了,什么叫动态创建对象?还有其他方式创建对象么?聪明的你应该想到了, 对象可以动态创建,也可以静态创建。静态创建的对象具备静态类型,动态创建的对象可以是静态类型也可以是动态类型。
二者区别如下:
静态类型: 声明时采用的类型,在编译时就已经确定
动态类型: 对象的实际类型,在运行时才能确定
下面是对象的创建的简单示例:
#include <iostream>
class CExample