Placement New

前几天写vector,可把我难倒了。最开始是一个测试用例,没有默认的构造函数,这个时候应该怎样去处理内存的分配。

我想到,既然一个元素的大小,即sizeof()是固定的,我们就可以先申请这个空间,等到需要使用的时候再赋值。

memcpy() 失败

虽然只学过C++化的简化版C语言,但我想到了malloc()方法,这就是一个只申请空间,不去填充空间的方法。

这对于传统的数据,就是说所谓的POD(Plain Old Data)是很好的。我的整个实现逻辑也是memcpy(),这样的处理速度快的多。

但是不是POD的类,占用了堆来存储部分内容,在他的存储空间里只存储了指向堆的指针。所以memcpy()只执行了浅拷贝,拷贝的实际上是指针,它指向的堆内存储是不变的。当原对象析构释放堆的时候,拷贝对象就被破坏了;被覆盖的对象没有进行析构而是直接被覆盖,内部申请的堆内存就被泄漏。

同样,当被覆盖的地方原本不存在对象,即只分配了内存却没有初始化内存空间时,如果直接调用类的赋值,这个赋值方法是不能检测原来的对象是否正确的。一旦有针对原指向堆内存的指针,现在是随机指针进行的操作,例如直接向动态数组发起memcpy(),就会出现段错误,或者内存的错误覆盖。

所以,凯撒的归凯撒,经过查阅资料,我找到了下面两个C++的处理方法。

placement new 成功

为什么我最开始不用new呢?因为new在调用的时候会自动调用构造函数,而一个用例没有默认构造函数,new就会出错。

怎么解决呢?经过资料的学习,我找到了placement new这个用法。实际上,new和delete是通过以下的过程实现的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
A* p=new A;					B* t=new B[_NUM];
delete p; delete [] t;

//<==>A* p=new A; B* t=new B[_NUM];
//the first step. This is equal to malloc(size_t).
operator new(sizeof(A)); operator new[](_NUM*sizeof(B));
//This is called 'placement new',
//to exec the constructor on the p location.
new(p) A(); for(size_t in=0;in<_NUM;in++)
new(t+in*sizeof(B)) B();

//<==>delete p; delete [] t;
//exec destroyer explicitly.
p->~A(); for(size_t in=0;in<_NUM;in++)
(t+in*sizeof(T))->~B();
//delete
operator delete p; operator delete [] t;

过程中的placement new实际上就是按需调用构造函数,而operator new/delete则是只申请内存而不初始化,和malloc/free功能是一致的。好像构造函数是不能够显式调用的,所以placement new来解决这个问题。

Ads by Google

Read our privacy policy on how these personalized advertisements are delivered to you.

For your reading experience, we provide full-text RSS feeds. Although math formulas cannot be displayed well, the interface can be adjusted as you like and there are no ads.