目录
1.c/c++内存分布
2.new与delete/malloc与free
c++内存管理方式:
new/delete操作内置类型:
new/delete操作自定义类型
operator new与operator delete函数
new和delete的实现原理
内置类型
自定义类型
malloc/free和new/delete的区别
1.c/c++内存分布
在学习c语言的时候我们就已经了解到不同的数据存储在不同的空间当中,对于内存,其被划分成不同的各个区域,分别用来管理不同的数据,如下图:
其次, c++在继承c语言的基础上,对于堆区上的申请和释放做了优化,这将体现在c++类和自定义数据类型中。
2.new与delete/malloc与free
首先我们知道如何利用c语言的方式向堆区上开辟空间,我们利用malloc,cealloc,realloc这三个函数可以实现向堆区上开辟一块空间,之后我们在进行初始化,在对空间的利用完之后,利用free函数释放掉对上的空间,实现动态内存管理。
int main()
{char* p1 = (char*)malloc(sizeof(char)*10); free(p1);char* p2 = (char*)calloc(char ("hello world"), sizeof(char)*10);char *p3 = (char*)realloc(p2, sizeof(char) * 10);free(p3);return 0;
}
对于c语言的动态内存管理:
1.首先大佬认为如此的设计使得动态内存管理过于冗余,对于空间的开辟较为麻烦。
2.我们需要强制类型转换并计算出所需该类型的大小。
c++内存管理方式:
new/delete操作内置类型:
我们能看到对于new的一些操作及运算符重载。
对于c++:我们可以利用new来进行动态内存的申请,利用delete进行内存的释放。
void Test()
{// 动态申请一个int类型的空间int* ptr4 = new int;// 动态申请一个int类型的空间并初始化为10int* ptr5 = new int(10);// 动态申请10个int类型的空间int* ptr6 = new int[3];//动态申请5个int类型的空间并初始化int *ptr7=new int[5]{1,2,3,4,5};delete ptr4;delete ptr5;delete[] ptr6;delete[] ptr7;
}
可以看到我们可以初始化空间,并且对于多个内存的开辟也更加方便,对于大小可以自己推导,如一个整型四个字节,一个字符型一个字节。
注意:这里在开辟多个或一个空间时,delete的写法也应与之对应,否则存在释放报错。
因为c++兼容c语言,所以除了书写简便,对于内置类型,功能是一样的。
new/delete操作自定义类型
如果仅仅是因为优化写法,那么在c++设计new和delete是纯属没有必要的,真正牛逼得地方是new与delete可以操作自定义类型!!!而这与c++11类和对象密切联系着。
利用malloc与free我们只能做到对空间的开辟与释放,但无法去初始化这个自定义类型的空间。
如自定义类型A:
class A
{
public:A(int a = 0): a(a){cout << "A():" << this << endl;}~A(){cout << "~A():" << this << endl;}void init_a(int x){_a = x;}
private:int a;
};
对于自定义类型下的malloc:
void test1()
{A* p1 = (A*)malloc(sizeof(A));//无法调用构造函数来初始化,因为当前无法显式调用构造函数p1->_a = 5;//也无法对私有数据操作,只能通过定义接口函数来初始化p1->init_a(5);//这也是对于简单的数据,若是设计的类中数据量偌大,则直接就g了free(p1);
}
我们可以看到自定义类型的数据要实现初始化太困难且复杂,甚至没法用。
那么对于重新设计的new与delete:
int main()
{// new/delete 和 malloc/free最大区别是 new/delete对于【自定义类型】除了开空间//还会调用构造函数和析构函数A* p1 = new A;A* p2 = new A(5);A* p3 = new A[2]{1,2};delete p1;delete p2;delete[]p3;return 0;
}
对于初始化new可以再申请空间后调用构造函数,对于释放delete会调用析构函数,之后在释放空间。
operator new与operator delete函数
// try to allocate size bytes
void *p;
while ((p = malloc(size)) == 0)
比特就业课
通过上述两个全局函数的实现知道,operator new 实际也是通过malloc来申请空间,如果
malloc申请空间成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施
就继续申请,否则就抛异常。operator delete 最终是通过free来释放空间的。
5. new和delete的实现原理
5.1 内置类型if (_callnewh(size) == 0){// report no memory// 如果申请内存失败了,这里会抛出bad_alloc 类型异常static const std::bad_alloc nomem;_RAISE(nomem);}
return (p);
}void operator delete(void *pUserData)
{_CrtMemBlockHeader * pHead;RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));if (pUserData == NULL)return;_mlock(_HEAP_LOCK); /* block other threads */__TRY/* get a pointer to memory block header */pHead = pHdr(pUserData);/* verify block type */_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));_free_dbg( pUserData, pHead->nBlockUse );__FINALLY_munlock(_HEAP_LOCK); /* release other threads */__END_TRY_FINALLYreturn;
}
/*
对于这里的new内存开辟失败的时候,这里设计利用异常进行判断。
new和delete的实现原理
内置类型
if (_callnewh(size) == 0){// report no memory// 如果申请内存失败了,这里会抛出bad_alloc 类型异常static const std::bad_alloc nomem;_RAISE(nomem);}
return (p);
}
/*
operator delete: 该函数最终是通过free来释放空间的
*/
void operator delete(void *pUserData)
{_CrtMemBlockHeader * pHead;RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));if (pUserData == NULL)return;_mlock(_HEAP_LOCK); /* block other threads */__TRY/* get a pointer to memory block header */pHead = pHdr(pUserData);/* verify block type */_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));_free_dbg( pUserData, pHead->nBlockUse );__FINALLY_munlock(_HEAP_LOCK); /* release other threads */__END_TRY_FINALLYreturn;
}
/*
free的实现
*/
#define free(p) _free_dbg(p, _NORMAL_BLOCK)