天天看点

More Effective C++ 08:理解各种不同含义的 new 和 delete

当你写这样的代码,你使用的

new

new

操作符。

这个操作符就像

sizeof

一样是语言内置的,你不能改变它的含义,它的功能总是一样的。它要完成的功能分成两部分。第一部分是分配足够的内存以便容纳所需类型的对象。第二部分是它调用构造函数初始化内存中的对象.

你所能改变的是如何为对象分配内存。

new

操作符调用一个函数来完成必需的内存分配,你能够重写或重载这个函数来改变它的行为。

new

操作符为分配内存所调用函数的名字是

operator new

函数

operator new

通常这样声明:

你一般不会直接调用

operator new

,但是一旦这么做,你可以像调用其它函数一样调用它:

operator new

将返回一个指针,指向一块足够容纳一个

string

类型对象的内存,它仅仅分配内存,不会调用构造函数。

当你的编译器遇见这样的语句:

它生成的代码或多或少与下面的代码相似:

void *memory = operator new(sizeof(string)); // 得到未经处理的内存为 String 对象 
call string::string("Memory Management") //初始化 
on *memory; // 内存中 
 // 的对象 
string *ps = static_cast<string*>(memory); // 是 ps 指针指向 新的对象
           

placement new

有时你确实想直接调用构造函数。在一个已存在的对象上调用构造函数是没有意义的,因为构造函数用来初始化对象,而一个对象仅仅能在给它初值时被初始化一次。但是有时你有一些已经被分配但是尚未处理的(raw)内存,你需要在这些内存中构造一个对象。你可以使用一个特殊的

operator new

,它被称为

placement new

下面是使用例子:

class Widget 
{ 
public: 
	Widget(int widgetSize); 
	... 
}; 
Widget * constructWidgetInBuffer(void *buffer, int widgetSize) 
{ 
	 return new (buffer) Widget(widgetSize); 
}
           

这个函数返回一个指针,指向一个Widget对象,对象在转递给函数的 buffer 里分配。

这初看上去有些陌生,但是它是

new

操作符的一个用法,需要使用一个额外的变量(buffer),当

new

操作符隐含调用

operator new

函数时,把这个变量传递给它。被调用的

operator new

函数除了待有强制的参数

size_t

外,还必须接受

void*

指针参数,指向构造对象占用的内存空间。

这个

operator new

就是

placement new

,它看上去像这样:

void * operator new(size_t, void *location) 
{ 
	return location; 
}
           

是这就是

placement new

需要做的事情。毕竟

operator new

的目的是为对象分配内存然后返回指向该内存的指针。在使用

placement new

的情况下,调用者已经获得了指向内存的指针,因为调用者知道对象应该放在哪里。

placement new

必须做的就是返回转递给它的指针

**

总结

你想在堆上建立一个对象,应该用

new

操作符。它既分配内存又为对象调用构造函数。

如果你仅仅想分配内存,就应该调用

operator new

函数;它不会调用构造函数。

如果你想定制自己的在堆对象被建立时的内存分配过程,你应该写你自己的

operator new

函数,然后使用

new

操作符,new 操作符会调用你定制的

operator new

如果你想在一块已经获得指针的内存里建立一个对象,应该用

placement new

删除和内存回收

函数

operator delete

delete

操作符的关系与

operator new

new

操作符的关系一样。

考虑一下代码:

string *ps; 
... 
delete ps;
           

你的编译器会生成代码来析构对象并释放对象占有的内存。

Operator delete

用来释放内存,它被这样声明:

导致编译器生成类似于这样的代码:

ps->~string(); 
operator delete(ps);
           

如果你只想处理未被初始化的内存,你应该绕过

new

delete

操作符,而调用

operator new

获得内存和

operator delete

释放内存给系统:

void *buffer = operator new(50*sizeof(char)); // 分配足够的 内存以容纳 50 个 char 
 //没有调用构造函数 
... 
operator delete(buffer); // 释放内存 
 // 没有调用析构函数
           

与在 C 中调用

malloc

free

等同。

数组

到目前为止我们所测试的都是一次建立一个对象。怎样分配数组?会发生什么?

被使用的

new

仍然是

new

操作符,但是建立数组时

new

操作符的行为与单个对象建立有少许不同。第一是内存不再用

operator new

分配,代替以等同的数组分配函数,叫做

operator new[]

它与

operator new

一样能被重载。这就允许你控制数组的内存分配,就像你能控制单个对象内存分配一样

string *ps = new string[10];
调用 operator new[]为 10 个 string 对象分配内存,
然后对每个数组元素调用string 对象的默认构造函数。
           

就像你能替换或重载

operator delete

一样,你也替换或重载

operator delete[]

继续阅读