new/delete是c++中动态构造对象的表达式 ,一般情况下的new/delete都是指的new/delete表达式,这是一个操作符,和sizeof一样,不能改变其意义。

new/delete表达式的声明如下:

::(optional) new (placement_params)(optional) ( type )initializer(optional)
::(optional) delete expression  

除了全局作用符::和初始化参数,还有个 placement_params,这是不常见的,要理解这个参数的作用,就要了解operator new和placement new。

众所周知,new表达式做了两个工作:1.分配内存;2.在分配的内存上调用构造函数构造对象。比如我们分配一个string对象

string *str = new string(“Kian”);

编译器首先调用operator new分配一块内存,类似于malloc,然后在mem上面调用构造函数,

1.void *mem = operator new(sizeof(string));

2. create string at men.

第二步我们是控制不了的,但是operator new却是可以修改的。

Operator new/delete的声明如下:

void* operator new  ( std::size_t count );
void* operator new ( std::size_t count, const std::nothrow_t& tag);
void operator delete ( void* ptr );
void operator delete ( void* ptr, const std::nothrow_t& tag);

第二种带参数tag的声明称为nothrow形式,因为现在的operator new如果分配内存失败的话会抛出bad_alloc异常. 有时候我们不想抛出异常,而是根据返回值判断内存分配失败与否,nothrow形式就是这个作用,失败时不抛出异常,而是返回null指针。

我们可以直接重载operator new, 定制自己的内存分配策略,常见的作用是优化内存使用性能。重载operator new不需要看见声明就可以直接使用。我们重定义一个简单的版本:

void* operator new(std::size_t size){
printf("operator new called, size=%d\n", size);
return malloc(size);
} void operator delete(void *ptr){
printf("operator delete called\n");
free(ptr);
} int main(){
int *i = new int();
delete i;
std::string *str = new std::string("Kian");
delete str;
}

运行结果:

operator new called, size=4

operator delete called

operator new called, size=4

operator new called, size=17

operator delete called

operator delete called

可是有时候我们希望拥有更多的功能,比如记录内存分配释放的位置,用于检测内存错误,或者直接在已有的内存上构造对象,那么必须定义更多参数,这就需要placement new/delete,声明如下.

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

可以直接在已有内存上构造对象:

void *mem = (void*)malloc(sizeof(int));
int *j = new(mem) int();
printf("mem=%p, j=%p, *j = %d\n",mem, j, *j);
free(mem);

运行结果:

mem=0x8a48008, j=0x8a48008, *j = 3

可以看出new直接在mem上面构造了对象。

目前,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 size){
printf("operator new called, size=%d\n", size);
return malloc(size);
} void operator delete(void *ptr){
printf("operator delete called\n");
free(ptr);
} void* operator new(std::size_t size, char* filename, int line){
printf("new called at %s:%d size=%d \n", filename, line, size);
return ::operator new(size);
} void operator delete(void *place, char* filename, int line) {
printf("delete called at %s:%d place=%p \n", filename, line, place);
::operator delete(place);
} int main(){
int *k = new(__FILE__, __LINE__) int();
printf("k=%p *k=%d \n", k, *k);
delete k;
}

运行结果:

new called at testnew.cpp:41  size=4

operator new called, size=4

k=0x847f008 *k=1

operator delete called

在每个new中打印了文件名和行号,不过细心的你会发现delete时并没有调用重载的placement delete ,这个delete只有在构造对象时抛出了异常才会调用,我们写一个简单的class来看看:

class ThrowExcept {
public:
ThrowExcept(int v):value_(v){ throw ;}
private:
int value_;
}; int main(){
ThrowExcept *t;
try{
t = new(__FILE__, __LINE__) ThrowExcept();
}catch(int &e){
printf("catch exception %d\n", e);
}
}

运行结果:

new called at testnew.cpp:53  size=4

operator new called, size=4

delete called at testnew.cpp:53  place=0x9e2e008

operator delete called

catch exception 1

自定义的delete被正常调用,这么做的原因在于如果构造函数抛出异常,系统正常的operator delete并不知道用户自定义的placement new做了什么,自然也不知道怎么去释放。所以如果自己定义placement new, 一定要定义对应的palcement delete,不然可能出现memory leak。

http://en.cppreference.com/w/cpp/memory/new/operator_new

http://en.cppreference.com/w/cpp/language/new

《effective/more effective c++》

new表达式,operator new和placement new介绍的更多相关文章

  1. new 、operator new 和 placement new

    一.原生operator new 我们先从原生operator new开始.考虑如下代码,它用来分配5个int型的空间并返回指向他们的指针[1]: int* v = static_cast<in ...

  2. C++ 中 new 操作符内幕:new operator、operator new、placement new

    一.new 操作符(new operator) 人们有时好像喜欢有益使C++语言的术语难以理解.比方说new操作符(new operator)和operator new的差别. 当你写这种代码: st ...

  3. C++中的new,operator new与placement new

    以下是C++中的new,operator new与placement new进行了详细的说明介绍,需要的朋友可以过来参考下     new operator/delete operator就是new和 ...

  4. 浅谈new operator、operator new和placement new 分类: C/C++ 2015-05-05 00:19 41人阅读 评论(0) 收藏

    浅谈new operator.operator new和placement new C++中使用new来产生一个存在于heap(堆)上对象时,实际上是调用了operator new函数和placeme ...

  5. 浅析C++内存分配与释放操作过程——三种方式可以分配内存new operator, operator new,placement new

    引言:C++中总共有三种方式可以分配内存,new operator, operator new,placement new. 一,new operator 这就是我们最常使用的 new 操作符.查看汇 ...

  6. 小结:c++中的new、operator new和placement new

    小结:c++中的new.operator new和placement new new(也称作new operator),是new 操作符,不可重载 class T{...}; T *t = new T ...

  7. C++中的new、operator new与placement new

    转:http://www.cnblogs.com/luxiaoxun/archive/2012/08/10/2631812.html new/delete与operator new/operator ...

  8. new、operator new、placement new

    首先我们区分下几个容易混淆的关键词: new.operator new.placement new new和delete操作符我们应该都用过,它们是对堆中的内存进行申请和释放,而这两个都是不能被重载的 ...

  9. C++ new operator, delete operator, operator new, operator delete, new placement

    http://www.younfor.com/cpp-new-placement-new-operator-new.html http://www.cnblogs.com/luxiaoxun/arch ...

随机推荐

  1. Kali-linux服务的指纹识别

    为了确保有一个成功的渗透测试,必须需要知道目标系统中服务的指纹信息.服务指纹信息包括服务端口.服务名和版本等.在Kali中,可以使用Nmap和Amap工具识别指纹信息.本节将介绍使用Nmap和Amap ...

  2. Week7:SVM难点记录

    1.函数dataset3Params(),如何计算模型估计偏差的? model=svmTrain(X,y,c_array,@(x1,x2)gaussianKernel(x1,x2,sigma_arra ...

  3. 使用Apache HttpClient 4.5设置超时时间

    使用HttpClient,一般都需要设置连接超时时间和获取数据超时时间.这两个参数很重要,目的是为了防止访问其他http服务时,由于超时导致自己的应用受影响. 4.5版本中,这两个参数的设置都抽象到了 ...

  4. Node 192.168.248.12:7001 is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0.

    [root@node00 src]# ./redis-trib.rb add-node --slave --master-id4f6424e47a2275d2b7696bfbf8588e8c4c3a5 ...

  5. Factory(工厂)模式

    设计模式一 工厂模式Factory 在面向对象编程中, 最通常的方法是一个new操作符产生一个对象实例,new操作符就是用来构造对象实例的.但是在一些情况下, new操作符直接生成对象会带来一些问题. ...

  6. vue中通过定义的数组循环将img的src引入图片却不显示图片问题解决方法

    需要前端循环图片数组将其放到页面中去. 需要将src渲染到页面中,如果单纯写src的路径会出现不显示图片的问题 因为图片路径在assets,所以需要require一下.

  7. 【星云测试】开发者测试(4)-采用精准测试工具对dubbo微服务应用进行测试

    简介:本文主要目的是把现今主流的Dubbo框架项目和精准测试进行对接,通过精准测试的数据穿透.数据采集.测试用例与代码的双向追溯.数据分析等一系列精准测试的特有功能达到对项目质量的保证. 本次环境搭建 ...

  8. MessageBox.Show用法

    private void button3_Click(object sender, EventArgs e) { MessageBox.Show("  1  个参数 "); } ~ ...

  9. 用 map 表达互斥逻辑

    在这个开发周期遇到这样一个需求: 管理员可以给子账号配置权限,有些权限存在互斥不可同时勾选,比如 审核员和代采.审核和采购员不可同时勾选 之前同事实现的方式如下: 这样每添加一个互斥关系就要遍历一次, ...

  10. yyy loves Maths VII(状压DP)

    题目背景 yyy对某些数字有着情有独钟的喜爱,他叫他们为幸运数字;然而他作死太多,所以把自己讨厌的数字成为"厄运数字" 题目描述 一群同学在和yyy玩一个游戏 每次,他们会给yyy ...