关于placement new
何为placement new呢?placement new 是重载operator new的一个标准、全局的版本,它不能被自定义的版本代替(不像普通的operator new和operator delete能够被替换成用户自定义的版本)。
首先我们区分下几个容易混淆的关键词:new operator、operator new、placement new 。
对于new operator,其实它是语言内建的,我们是没有办法改变它的。当我们创建了一个new表达式时,会发生两件事。首先,使用operator new()分配内存,然后调用构造函数。现在明白了吧,new operator会去调用operator new()跟创建对象的构造函数,我们能控制的,只有内存的分配函数operator new()(对于operator delete()也是一样)。所谓控制,其实就是重载这个函数,编译器将用重载的operator new代替默认的版本去分配内存。
接下来就是要说的placement new了。其实它也是operator new重载的一个版本,只是很少人用到它。它有一个特点,就是允许你在已经分配好的内存上创建一个对象,也就是说,可以通过某种手段在指定的内存创建对象。
好了,说到这里,我们就可以利用它来做一些高效率的事情了。
当我们用new分配对象数组空间时,会自动调用对象的默认构造函数。可是如果数组只有一部分元素会被使用,或者元素立即被赋值,那刚刚自动调用对象的默认构造函数不就等于白做了吗?这时候placement new就发挥作用了,因为它可以在分配好的缓冲区上创建对象。采用这种方式,缓冲区占用的存储区的分配,可以避免被默认的构造函数初始化:
const size_t n = sizeof(string) * 30;
string *sbuf = static_cast<string *>(::operator new(n));/*这时候是直接调用operator new函数来分配内存的,也就是说,只会分配空间,类似于malloc。*/
下面是一个在分配好的内存空间上创建对象的函数:
void append(string buf[], int &size, const string &val)
{new (&buf[size++] string(val);}//palcement new
这样的话,我们就可以在需要的情况下使用pacement new通过复制构造函数来初始化数组里的元素,在一些情况下能够提高程序的效率。
但这样的话我们就得自己来负责清理工作了,凡事有利必有弊吧。
这里得通过显式调用string的析构函数,如:
buf[size].~string();
并用operator delete来释放存储区:
::operator delete(buf);