string *ps = new string("Memory Management");
当你写这样的代码,你使用的new
是new
操作符。
这个操作符就像sizeof
一样是语言内置的,你不能改变它的含义,它的功能总是一样的。它要完成的功能分成两部分。第一部分是分配足够的内存以便容纳所需类型的对象。第二部分是它调用构造函数初始化内存中的对象.
你所能改变的是如何为对象分配内存。new
操作符调用一个函数来完成必需的内存分配,你能够重写或重载这个函数来改变它的行为。new
操作符为分配内存所调用函数的名字是operator new
。
函数operator new
通常这样声明:
void * operator new(size_t size);
你一般不会直接调用 operator new
,但是一旦这么做,你可以像调用其它函数一样调用它:
void *rawMemory = operator new(sizeof(string));
operator new
将返回一个指针,指向一块足够容纳一个 string
类型对象的内存,它仅仅分配内存,不会调用构造函数。
当你的编译器遇见这样的语句:
string *ps = new string("Memory Management");
它生成的代码或多或少与下面的代码相似:
void *memory = operator new(sizeof(string)); // 得到未经处理的内存为 String 对象
call string::string("Memory Management") //初始化
on *memory; // 内存中
// 的对象
string *ps = static_cast<string*>(memory); // 是 ps 指针指向 新的对象
有时你确实想直接调用构造函数。在一个已存在的对象上调用构造函数是没有意义的,因为构造函数用来初始化对象,而一个对象仅仅能在给它初值时被初始化一次。但是有时你有一些已经被分配但是尚未处理的(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) Widget(widgetSize)
这初看上去有些陌生,但是它是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
用来释放内存,它被这样声明:
void operator delete(void *memoryToBeDeallocated);
delete ps;
导致编译器生成类似于这样的代码:
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
等同。
到目前为止我们所测试的都是一次建立一个对象。怎样分配数组?会发生什么?
string *ps = new string[10];
被使用的 new
仍然是 new
操作符,但是建立数组时 new
操作符的行为与单个对象建立有少许不同。第一是内存不再用 operator new
分配,代替以等同的数组分配函数,叫做operator new[]
它与 operator new
一样能被重载。这就允许你控制数组的内存分配,就像你能控制单个对象内存分配一样
string *ps = new string[10];
调用 operator new[]为 10 个 string 对象分配内存,
然后对每个数组元素调用string 对象的默认构造函数。
就像你能替换或重载 operator delete
一样,你也替换或重载 operator delete[]