2008年10月16日星期四

Placement New的用法

在《C++中控制对象的创建》一文中,我曾经提到Placement New的一些用法。最近一段时间很碰巧用到了这个技术,因此有了更深刻的一些理解。

Placement New的原型很简单:


inline void* operator new (size_t t, void* p) {
return p;
}


可以看出,它仅仅就是返回传给他的那个指针地址,大小t不使用。
因此,我们一般先申请一块内存,然后用placement new在初始化一个对象。这里的初始化的意思就是先把那块内存映射成对象地址空间,然后再起始地址调用对象的构造函数。例如:


class Window
{
int width_, height_;
public:
....
Window(){}; // default ctor
Window(int w, int h){...}; // ctor with predefined height and width
}

void* p = (Window*)malloc(sizeof(Window));
Window* pWin = new(p) Window();
.... //use pWin
pWin->~Window();
free(p);

在上面的代码中,最后第二行很重要。一般来说,析构函数是当自动变量离开作用域时自动调用或者使用delete时调用。但是使用placement new时,不能在该对象上面使用delete操作,因此析构函数不会被自动调用。我们必须使用一种比较少见的方式——手动调用析构函数来释放在构造函数中获取的资源。

Placement new还常常用于对象数组的创建上。一般使用new[](读作array new)来创建对象数组的时候有一个缺点,就是只能调用其默认构造函数。这有时候非常不方便。

Window* pArrayWin = new Window[20]; //default ctor is called

但是使用placement new就可以让我们获得调用其他构造函数的能力。代码如下:

Window* pArrayWin = (Window*)(operator new(sizeof(Window)*20)); //
i = -1;
while( i <20){
Window* pTemp = new(&pArrayWin[i++])Window(i*i,i*i*i);
}


这里就可以使用Window类的另外一个构造函数了。在每一个Window类构造的时候就可以给其设置长和宽。
这里的Window类只有两个整型成员,这种情况下,可以不用调用其析构函数,直接delete分配的内存。因此用placement new来处理这种小型连续数据在某种程度上可以提高效率。

没有评论: