在看过《 Inside the C++ Object Model》的关于new和delete的语意讲解后,对new和delete有了一定程度上的深入了解~~
当我们使用new给我们的一个对象分配空间的时候。。。new内部的调用实际上是
void* operator new(size_t)
{
//alloc memory
//then call class's constructor
}
首先分配了空间。。。但是不会调用我们该类的构造函数
在这期间,则C++的RTTI机制会进行暗箱操作~~~
相应的delete也是如此,RTTI也会对其进行干涉
首先调用该类的析构
然后再进行释放...
然而new是一个运算符,并且可以重载,所以在C++中还有一种威力强大的placement new and placement delete
他的重载则是
void * operator new(size_t t,void *p)
{
return p;
}
同理,RTTI也会使new调用相应的构造函数
但是我们这样做
char *buf=new char[sizeof(typename)];
typename *obj=(typename*)operator new(sizeof(typename),buf);
//这句则只会在buf的所指向的堆内存处给我这个类分配一个typename长度的空间,但是不会去调用构造函数
obj=new(buf) typename;
//这句则是在buf处分配了空间,并且调用构造函数
这就是placement new的强大之处,我们可以在指定的内存处进行我们的对象的构造
但是,如果现在这个对象不需要了,我们还需要在这片内存上构造我们的另一个该类对象,该如何去做呢?
obj->~typename();//??
这样可以,但是却显的很生硬
delete obj;//??
这句正确,但是同样也释放了obj对象的内存空间,那要怎么做呢?
所以C++也提供了对应placement new的placement delete
可以这样进行调用
delete(buf,obj);
//这句则不会对obj的内存进行释放,只调用析构函数,所以,我们如果要继续在该片内存上构造对象,可以如下
typename *_obj=new(buf) typename;
由此看来,placement new和placement delete的强大之处,可以让程序员更灵活的去操作我们的内存单元,让一片内存连续使用,而省去来回的申请和来回的释放过程,更加的提高了编程的效率。
不过,有一点,placement new和placement delete不支持多态,倘若我们有如下代码
struct Base { int j; virtual void f(); };
struct Derived : Base { void f(); };
void fooBar()
{
Base b;
b.f();// Base::f() invoked b.
~Base();
new ( &b ) Derived; // placement new
b.f(); // which f() invoked?
}
这是原书上的代码,最后一句,我们调用的f()是哪个类的呢?
很多用户都希望调用Derived的f(),因为Base中的f()是virtual的
但事与愿违,经过placement new之后,多态并没有体现出来
大多的编译器编译后都会去调用Base的f()。
综上,new和delete在内部实现上,是如何去分配空间并调用对应类型的构造函数已经很明了。
初始其实和C中的malloc和free一样,但是有了RTTI机制,则会在运行时计算类型,从而决定调用哪个类的构造函数。
RTTI实现时,若类中没有一个虚函数,则将在编译过程中静态的计算类型,更多可以参考《 Inside the C++ Object Model》7.3。
若至少有一个虚函数存在,则RTTI在运行时动态的计算类型。
好了,这是我看过之后所领悟到的,写到这,怕自己忘记了。
发表于 @ 2009年09月01日 21:49:00
原文链接: https://www.cnblogs.com/zjj9850/archive/2010/09/13/1824861.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/14942
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!