new表达式,operator new和placement new介绍
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介绍的更多相关文章
- new 、operator new 和 placement new
一.原生operator new 我们先从原生operator new开始.考虑如下代码,它用来分配5个int型的空间并返回指向他们的指针[1]: int* v = static_cast<in ...
- C++ 中 new 操作符内幕:new operator、operator new、placement new
一.new 操作符(new operator) 人们有时好像喜欢有益使C++语言的术语难以理解.比方说new操作符(new operator)和operator new的差别. 当你写这种代码: st ...
- C++中的new,operator new与placement new
以下是C++中的new,operator new与placement new进行了详细的说明介绍,需要的朋友可以过来参考下 new operator/delete operator就是new和 ...
- 浅谈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 ...
- 浅析C++内存分配与释放操作过程——三种方式可以分配内存new operator, operator new,placement new
引言:C++中总共有三种方式可以分配内存,new operator, operator new,placement new. 一,new operator 这就是我们最常使用的 new 操作符.查看汇 ...
- 小结:c++中的new、operator new和placement new
小结:c++中的new.operator new和placement new new(也称作new operator),是new 操作符,不可重载 class T{...}; T *t = new T ...
- C++中的new、operator new与placement new
转:http://www.cnblogs.com/luxiaoxun/archive/2012/08/10/2631812.html new/delete与operator new/operator ...
- new、operator new、placement new
首先我们区分下几个容易混淆的关键词: new.operator new.placement new new和delete操作符我们应该都用过,它们是对堆中的内存进行申请和释放,而这两个都是不能被重载的 ...
- 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 ...
随机推荐
- 27、springboot整合RabbitMQ(1)
RabbitMQ整合 使用dockers下载带management的版本,该版本是带web界面的,可操作性比较强
- sqoop导数据到hive报错
[root@hadoop1 conf]# sqoop import --connect jdbc:mysql://192.168.122.15:3306/company --username sqoo ...
- EF Core 中多次从数据库查询实体数据,DbContext跟踪实体的情况
使用EF Core时,如果多次从数据库中查询一个表的同一行数据,DbContext中跟踪(track)的实体到底有几个呢?我们下面就分情况讨论下. 数据库 首先我们的数据库中有一个Person表,其建 ...
- SQL Server 数据库空间使用情况
GO /****** Object: StoredProcedure [dbo].[SpaceUsed] Script Date: 2017-12-01 11:15:11 ******/ SET AN ...
- 【腾讯敏捷转型No.6】如何打造称手的敏捷工具
通常情况下,大家对于敏捷的感受就是:大家一起来开站立晨会啦!然后一大早,大家拿着早餐,围成一个圈,听一个人在讲话. 在很多公司,决定采用敏捷之后,都会从晨会开始,因为很多人觉得敏捷其它模块都很难学习, ...
- 转发: Angular装饰器
Angular中的装饰器是一个函数,它将元数据添加到类.类成员(属性.方法)和函数参数. 用法:要想应用装饰器,把它放在被装饰对象的上面或左边. Angular使用自己的一套装饰器来实现应用程序各部件 ...
- 使用属性Props完成一张卡片
一:我们先安装bootstrap,为了使我们的样式好看些 cnpm install bootstrap --save 二:我们在index.js中引入bootstap Import ‘bootst ...
- 浅谈 Virtual DOM 的那些事
背景 我们都知道频繁的dom给我们带来的代价是昂贵的,例如我们有时候需要去更新Table 的部分数据,必须去重新重绘表格,这代价实在是太大了,相比于频繁的手动去操作dom而带来性能问题,vdom很好的 ...
- 腾讯云的对象存储COS
什么是对象存储COS Clound Object Storage,COS,专门为企业和开发者们提供能够存储海量的分布式存储服务,用户可以随时通过互联网对大量数据进行批量存储和处理,在任意位置存储和检索 ...
- Tomcat优化(心得经验)
最近用httpclient做performance testing时,发现当线程加到150时服务端就会抛出socket资源用尽的错误,根本没法再往上加,响应的速度也是相当的慢,后来经过研究,发现在se ...