您的位置:首页 > 编程语言 > C语言/C++

new................未完待续

2016-03-07 19:25 295 查看
new表达式用于动态创建对象,与此对应用于销毁对象的还有delete exprssion,有点类似于C中的malloc和free吧。

C++primer上说,当使用一条new表达式的时候实际上有三步:创建内存(调用一个 operator new 或 operator new[ ]的库函数),调用构造函数,返回内存地址。这里面能拿出来说的就第一步,调用operator new的库函数。

其实就是一个重载的运算符,和普通的运算符重载没多大区别。其中new的定位形式有必要说一下。定位new 也叫placement new,它的形式如下:

void* operator new  ( std::size_t count, void* ptr );
void* operator new[]( std::size_t count, void* ptr );
void* operator new  ( std::size_t count, user-defined-args... );
void* operator new[]( std::size_t count, user-defined-args... );


它除了可以接受一个size_t参数外,还可以接受一个地址参数
void * ptr
。同时这个版本是没办法重载的,当时用这个形式的placement new的时候,这个函数是不分配任何内存的,它除了把我们指定的地址参数返回之外,什么都没做。我试了一下

operator new(2012111063,ptr)


这样的写法根本不会失败,即使你把那个内存大小的参数改为long 的最大值或者任意大的数值失败。

设计这个的用处之一就体现在了标准库容器vector的设计上,vector是一个可变数组,所以其中肯定涉及到了扩容的问题,然而如果要扩容,可能需要复制原来容器中的数据,如果容器里数据很多,则来来回回的复制肯定会降低程序效率。如果你的内存分配用placement new就可以避免复制的问题。我写了个程序验证了自己的猜想:

#include <iostream>
#include <new>
#include <cstdlib>
using namespace std;
const int MAX=2012111063;
void * operator new(size_t fuck,string s){
void * p=(void*)malloc(sizeof(int));
cout<<s<<endl;
return p;
}
int main(int argc,char **argv){
int * p=new int();
printf("first time addrss: %p\n",&p);
p=new(p)int[100];   //first time placement new
//assgin
for(int i=0;i<100;i++)
p[i]=i+1;
printf("second time addrss: %p\n",&p);

printf("the content of the array: \n");
for(int i=0;i<100;i++)
cout<<p[i]<<" ";
cout<<endl;

p=new(p)int[200];  //second time placement
printf("third time addrss: %p\n",&p);
printf("the content of the array: \n");

for(int i=0;i<100;i++)
cout<<p[i]<<" ";
cout<<endl;
return 0;
}


上面这个程序的输出为:



用了两次placement new来分配内存(实际上就是扩容),前后两次P的地址是相同的,同时p的前100个元素不变。

这正好就对应的vector的设计,而vector的内存分配器就是allocator,allocator的功能就是把内存构造和对象创建分开,其中应该用到了operator new的定位形式。

不过至于new是用什么来动态创建内存的,很多人会想到是C中的malloc之类的,不过我个人觉得应该不是。malloc一般是首次适应和最佳适应两种之一,new分配的内存区域好像很大。有可能是从空闲链表块中找一个最大的空闲区。不过这些我也不确定,我有空会再看看。

未完待续,欢迎指出错误!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  C++