登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

图像处理 视频分析 机器视觉 模式识别

方向比努力更重要

 
 
 

日志

 
 
关于我

河北软件开发项目,电子警察卡口项目,公安天网项目,媒体流处理,数字图像处理。媒体服务器 RTSP、图像处理、车牌识别……DCT变换,H.264压缩

new操作符  

2010-01-06 10:12:43|  分类: C + 算法 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
通常,new负责在堆内存中找到一个能够满足要求的内存块。new操作符还有一种变体:placement new 操作符,它能让你指定要使用的内存的位置。 程序员可以使用这种特性来设置其内存管理规程或处理需要通过特定地址进行访问的硬件。
要使placement new,首先需要包含头文件new,下面的代码段演示了new操作符的用法:

#include <new>
#include <iostream>
using namespace std;

struct chaff{
    char a[20];
    int flag;
};

char buffer1[50];
char buffer2[500];

int main(){
    cout<<\"Buffer1 at \"<<(void*)buffer1<<endl;
    cout<<\"Buffer2 at \"<<(void*)buffer2<<endl;

    chaff *p0,*p1,*p2;
    int *p3,*p4,*p5;

    p0=new chaff;
    p3=new int[20];
    cout<<\"p0 at \"<<p0<<endl;
    cout<<\"p3 at \"<<p3<<endl;
    delete p0;
    delete [] p3;

    p1=new (buffer1) chaff;
    p4=new (buffer2) int [20];
    cout<<\"p1 at \"<<p1<<endl;
    cout<<\"p4 at \"<<p4<<endl;

    p2=new (buffer1) chaff;
    p5=new (buffer2+100) int [20];
    cout<<\"p2 at \"<<p2<<endl;
    cout<<\"p5 at \"<<p5<<endl;

    return 0;
}


在上面的代码段中,对p1和p4使用了placement new操作符。这意味着,p1将使用以buffer1为首地址的内存块,而p4将使用以buffer2为首地址的内存块。下面的第二次使用placement new 操作符,p2将使用buffer1为首地址的内存块,而p5将使用buffer2首址+100的内存地址为起始地址的内存块。
程序在我机器上的输出如下:
Buffer1 at 0x437000
Buffer2 at 0x437040
p0 at 0x3d3e68
p3 at 0x3d3e88
p1 at 0x437000
p4 at 0x437040
p2 at 0x437000
p5 at 0x4370a4

当然,你可能会觉得程序有点奇怪。p1和p2都使用了以buffer1为首地址的内存。这样p2会不会将p1覆盖?另外使用placement new操作符的地方没有用delete语句释放内存。这样会不会出问题。答案是:不会。事实上,placement new操作符使用的是静态内存,而不是动态分配的内存。这就意味着,不能用delete操作符来对它进行内存释放。这就跟这样写一样:
int a;
delete a;
这反而会引发运行时错误。而你担心的p2将p1覆盖的问题,事实上并不会存在,但是p1和p2会指向同一块内存!我们可以在上面的程序的最下面加上这样的一段代码:
    strcpy(p2->a,\"hello\");
    p2->flag=100;

    cout<<\"p2->a = \"<<p2->a<<endl;
    cout<<\"p2->flag = \"<<p2->flag<<endl;
    cout<<\"p1->a = \"<<p1->a<<endl;
    cout<<\"p1->flag = \"<<p1->flag<<endl;

查看这时的输出,你会发现,p1和p2其实是完全一样的!

虽然有三种new的用法,但是分为两大类也未尝不可,那么是哪两类呢?

 

其一是new operator,也叫new表达式;

其二是operator new,也叫new操作符。

 

这两个英文名称起的也太绝了,很容易搞混,那就记中文名称吧。new表达式比较常见,也最常用,

例如:
string* ps = new string("abc");
上面这个new表达式完成了两件事情:申请内存和初始化对象。

 

 


new操作符类似于C语言中的malloc,只是负责申请内存,例如:
void* buffer = operator new(sizeof(string));
注意这里多了一个operator。这是new的第二个用法,也算比较常见吧。

 


那么第三个用法就不很常见了,官方的说法是placement new,它用于在给定的内存中初始化对象,也就是说你手中已有一块闲置的内存,例如:
void* buffer = operator new(sizeof(string));
//那么现在buffer是你所拥有闲置内存的指针
buffer = new(buffer) string("abc"); //调用了placement new,在buffer所指向的内存中初始化string类型的对象,初始值是"abc"
事实上,placement new也是new表达式的一种,但是比普通的new表达式多了一个参数,当然完成的操作和返回值也不同。
因此上面new的第一种用法可以分解两个动作,分别为后面的两种用法。

 

 

 

与new对应的delete没有三种语法,它只有两种,分别是delete operator和operator delete,也称为delete表达式和delete操作符。delete表达式和new表达式对应,完成对象的析构和内存的释放操作。而delete操作符只是用于内存的释放,和C语言中的free相似。例如:
string* ps = new string("abc");
...
delete ps; //调用delete表达式,先析构再释放
void* buffer = operator new(sizeof(string));
...
operator delete(buffer); //释放
那么为什么没有和placement new对应的那个delete呢?其实是有的。placement new是在指定位置初始化对象,也就是调用了构造函数,因此与之对应的就是析构函数了,只不过它不叫placement delete而已。
void *pv = operator new(sizeof(vector<int>));
pv = new(pv) vector<int>(8, 0);
...
static_cast<vector<int>* >(pv)->~vector(); // call destruct function
operator delete(pv); // free memory
pv = NULL;

  评论这张
 
阅读(909)| 评论(0)

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018