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. jQuery .attr()和.removeAttr()方法操作元素属性示例

    今天主要和大家一起分享一下如何使用jQuery的.attr()和.removeAttr()方法读取,添加,修改,删除元素的属性.大家在平时的Web页面制作中都有碰到如何动态的获取元素的属性和属性值,或 ...

  2. 将宿主主机上的目录挂载到Docker中

    docker run -it -v /home/zhouqun/文档/workplace:/var/www/html ubuntu64 /bin/bash 将宿主主机中/home/文档/workpla ...

  3. Dubbo实践(十三)Export

    Spring在启动Dubbo服务端应用时,会实例化ServiceBean<T>并设置配置属性,然后调用export方法: @SuppressWarnings({"unchecke ...

  4. LWIP network interface 即 LWIP 的 硬件 数据 接口 移植 详解 STM32 以太网数据 到达 的第二站: void ethernetif_input( void * pvParameters )

    根据 上一篇 文章 , ETH  DMA 数据中断 会 发送 一个信号量 ,我使用 全局 搜索 这个信号量 s_xSemaphore 得到 一下 几个 值 根据 这个 分析  我们找到了   数据 的 ...

  5. spring cloud config将配置存储在数据库中

    Spring Cloud Config Server最常见是将配置文件放在本地或者远程Git仓库,放在本地是将将所有的配置文件统一写在Config Server工程目录下,如果需要修改配置,需要重启c ...

  6. CSP 试题编号201803-1 Java实现

    import java.util.Scanner; public class Main{ public static void main(String[] args) { Scanner input ...

  7. DDL-表的管理

    一.创建表 ★create table [if not exists] 表名(    字段名 字段类型 [约束],    字段名 字段类型 [约束],    ...    字段名 字段类型 [约束] ...

  8. iOS中怎么判断可变和不可变的坑(更正版)

    iOS中怎么判断可变和不可变的坑 怎么判断NSString和NSMutableString呢 看题 BOOL result = [" isKindOfClass:[NSMutableStri ...

  9. JQuery简单总结(思维导图)

  10. php向页面输出中文时出现乱码的解决方法

    今天,刚刚学习PHP发现用echo输出中文时,页面会出现乱码,然后查了一下资料说是浏览器编码格式有问题,要改成utf-8.但是每个人的浏览器编码可能会有所不同,所以找到了一个很好的解决方法, 就是在p ...