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. [Python 网络编程] makefile (三)

    socket.makefile(mode ='r',buffering = None,*,encoding = None,errors = None,newline = None )返回一个与套接字相 ...

  2. SpringBoot实战(三)之使用RestFul Web服务

    一.导入maven依赖 <?xml version="1.0" encoding="UTF-8"?> <project xmlns=" ...

  3. 【luogu P3953 逛公园】 题解

    题目链接:https://www.luogu.org/problemnew/show/P3953 题外话:感觉2017年神题好多..这还不是最神的一道,真在考场上我也就写个最短路计数暴力了.现在在大佬 ...

  4. C#中调用方法

    using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threa ...

  5. 1<=portNo<=4竟然在keil4.71里面不报错

    1.if( 1<=portNo<=4 ) {  CardIn2_CS_L; //pull low  CardIn1_CS_H;  CardOut1_CS_H;  CardOut2_CS_H ...

  6. docker 容器不能访问宿主端口原因

    因为数据包到了eth0的 上的iptables 表,首先匹配PREROUTING 链,这个拒绝了来自docker0的流量,从而跳到input链,input没有放开服务端口,所以容器访问宿主端口失败;但 ...

  7. Ubuntu如何挂载U盘

    1. 以root用户登陆 2. 查看当前挂载 fdisk -l 一般情况未挂载的硬盘都在最后,这里是/dev/sdb1 3.新建一个目录来挂载硬盘 挂载到MNT/usb root@h-Default- ...

  8. MongoDB的入门

    MongoDB mongodb是非关系型数据库 对于关系型数据库,存储数据的时候需要提前建表建库,随着数据的复杂度越来越高,所建的表的数量也越来越多:但是非关系型却不需要 mongodb的基本的命令的 ...

  9. 【DB2数据库在windows平台上的安装】

  10. spring data elasticsearch 使用

    很久之前就安装了elasticsearch,一直没用java用过,最近看了一下spring data系列的elasticsearch,这里写一篇心得. 如果尚未安装elasticsearch,可以 参 ...