问题:
在看stl源码的时候,发现new 还可以这么调用:
T* tmp = (T*)(::operator new((size_t)(sizeof(T) * n)));
这个调用很类似于malloc
这样的形式,而且参数是以字节为主的,这和我平时使用的new 不一样的,那么::operator new
是不是更加底层的函数,也就是上层的new
其实是通过调用这个函数来申请空间的呢?
解答:
首先在这里需要明白一个前提:
operator new /operator delete 和 new operator / delete operator这两种的区别,我们通常使用的是new operator/delete operator,而我们通常在类中重载的是operator new / operator delete.在区别就是前者是库函数,而后者是操作运算符;
对于两者的区别:
new operator/delete operator:这两个操作里面包含了两个过程:
- 申请空间.
- 在申请好的空间上调用对象的构造函数进行初始化的.
而delete则是析构+释放内存,而这就是它们的作用的;而这两者是不能被重载的,网上的解释说这两者是不能被重载的,C++标准规定这两者的行为不应该也不能够被改变的;
operator new/operator delete:其实这两个有点类似于C中的malloc和free,因为他们只是负责申请空间和释放空间,而且他们接受的参数也是字节数,这和malloc和free几乎是一模一样,不过他们的使用必须要配对着,new出来的内存必须用delete才能释放掉;而且他们可以被用来重载,通常在类域中被重载,从而达到高效的内存分配。
new operator的过程:
1.调用operator new来申请空间:ptr = ::operator new(sizeof(T))
2.然后调用构造函数进行初始化;
而就是这2步是不能变化的,这也保证了new operator
的行为是不变的,如果我们对operator new
进行重载的话,那么就可以改变new operator
的第一步,编译器会调用类中的重载过的new
,与此同时,我们也要重载了operator delete
,因为要对应起来,这样的话不会导致内存泄漏;
程序和运行结果表示了我的想法,而且如果你自己不重载operator delete
的话,那么编译器会自动的调用全局的delete
,也就是::operator delete
对operator new的重载注意点:
- 返回值一定要为void*(其实这比较好理解,因为这个只是用来申请空间的,而没有初始化,所以返回void*是应该的)
- 参数为size,是字节数
- 重载时可以携带其他的参数(如果你给与了参数,那么你在使用new的时候,必须写上你的参数,比如
new("hello") int(5));
2.placement new(定义:如果operator new 接受除size以后的参数,那么这个operator new 就是placement new)
对于这个我们平常可以看见的就是有这样的语句
new (ptr) int(5);
对于这样的语句,可能比较奇怪,因为通常我们都是这么使用new的,new int(5),其实上面的就是placement new;
placement new:其实是operator new的一个重载版本,但是关键在于它是重载operator new 的一个标准、全局的版本,它不能够被自定义的版本代替
其实对于这句话我还是不能很好的理解的,做一个实验吧?
这是我在全局范围内定义了一个placement new,当然运行的结果是这个函数已经定义过了,所以error;因为这是一个全局范围内的,而正式的placement new以前在标准库的某一个地方定义过来了,所以不能我重新定义;
关于placement new 的效果就是在已经存在的内存块上构造一个对象的;new(ptr) A(),这就表示在ptr指定的地方构造A对象的;
按书上所说,这个特殊的placement new 是定义在<new>文件中的,它的原型就是:
其实这个函数真的很简单,只是很简单的返回了p这个参数,关于这个问题其实我也不是很明白?不过书上的意思是说这个new可以调用构造函数,所以比较好。
对于placement new这样的new来说,必须要匹配对应的placement delete,也就是附带的参数要和new 是一样的,而这样的delete的用处只有一个,当new在分配内存的时候发生异常,这个时候编译器会寻找一个delete来处理这个问题,如果没有定义相应的placement delete的话,这个时候编译器就什么都不做了,如果定义了,那么就会使用这个delete来做一些还原的工作的;placement delete除了这个工作,其他没有任何作用,对于一个指针使用delete是绝对不会调用placement delete的,绝对不会,不会;
对于一个指针使用delete来说,通常调用就2个,一个是全局的delete的,一个是类中的operator delete;
最后看一些关于全局的placement delete的源代码
可以看出来,它其实什么都没有做的;在深入探索