建议29:区分new的三种形态
C++语言一直被认为是复杂编程语言中的杰出代表之一,不仅仅是因为其繁缛的语法规则,还因为其晦涩的术语。下面要讲的就是你的老熟人—new:
它是一个内存管理的操作符,能够从堆中划分一块区域,自动调用构造函数,动态地创建某种特定类型的数据,最后返回该区域的指针。该数据使用完后,应调用delete运算符,释放动态申请的这块内存。
如果这就是你对new的所有认识,那么我不得不说,你依旧被new的和善外表所蒙蔽着。看似简单的new其实有着三种不同的外衣。
是的,你没有看错,也不用感到惊奇,一个简单的new确实有三种不同的形态,它扮演着三种不同的角色,如下所示:
|
下面的代码片段展示的是我们印象中熟悉的那个new:
|
这里所使用的new是它的第一种形态new operator。它与sizeof有几分类似,它是语言内建的,不能重载,也不能改变其行为,无论何时何地它所做的有且只有以下三件事,如图3-2所示。
图3-2 new operator所完成的三件事
所以当写出“string *pStr = new string("Memory Management");”代码时,它其实做的就是以下几件事:
|
其实new operator背后还藏着一个秘密,即它在执行过程中,与其余的两种形态都发生了密切的关系:第一步的内存申请是通过operator new完成的;而在第二步中,关于调用什么构造函数,则由new的另外一种形态placement new来决定的。
对于new的第二种形态—内存申请中所调用的operator new,它只是一个长着“明星脸”的普通运算符,具有和加减乘除操作符一样的地位,因此它也是可以重载的。
operator new在默认情况下首先会调用分配内存的代码,尝试从堆上得到一段空间,同时它对事情的结果做了最充分的准备:如果成功则直接返回;否则,就转而去调用一个new_hander,然后继续重复前面过程,直到异常抛出为止。所以如果operator new要返回,必须满足以下条件之一:
内存成功分配。
抛出bad_alloc异常。