上一节介绍了new运算符的常规用法,这一节我们一起来看看定位new运算符的用法。
1、定位new运算符是在已分配的内存空间进行二次分配。例如:
char *buffer = new char[512];
Point *p = new (buffer) Point(); //Point为类名
Point *q = new (buffer + sizeof(Point)) Point();
即:在内存缓冲区buffe中创建对象p、q
2、delete与常规new运算符配合使用,但不能与定位new运算符使用,只能使用定位new运算符创建的对象调用析构函数,例如:
p->~Point();
3、对于使用定位new运算符创建的对象,应与创建顺序相反的顺序进行删除,因为晚创建的对象可能依赖于早创建的对象。仅当所有对象被销毁之后,才能释放用于存储这些对象的缓冲区
接下来我们来看一具体例子(参照c++ primer plus):
-------------------------------------------------------------
#include<iostream>
#include<string>
#include<new>
using namespace std;
const int BUF = 512;
class Test
{
private:
string words;
int number;
public:
Test(const string & s = "Test", int n = 0)
{
words =s;
number = n;
cout << words << " constructed\n";
}
~Test()
{
cout << words << " destroyed\n";
}
void Show()
{
cout << words << ", " << number << endl;
}
};
int main()
{
char * buffer = new char [BUF];
Test *p1, *p2;
p1 = new (buffer) Test;
p2 = new Test("heap1", 20);
cout << "memory block addresses:\n"
<< "buffer: "
<< (void*) buffer
<< " heap: "
<< p2
<<endl;
cout << "memory contents:\n";
cout << p1 << ": ";
p1->Show();
cout << p2 << ": ";
p2->Show();
Test *p3, *p4;
p3 = new (buffer + sizeof(Test)) Test("place object in buffer", 6);
p4 = new Test("heap2", 10);
cout << "memory contents:\n";
cout << p3 << ": ";
p3->Show();
cout << p4 << ": ";
p4->Show();
delete p2;
delete p4;
p3->~Test();
p1->~Test();
delete [] buffer;
cout << "Done\n";
return 0;
}
-------------------------------------------------------------
程序运行结果如下:
我们注意到:
程序在已创建的内存缓冲区中,再次创建两个Test对象。并且在最后程序显式地为使用定位new运算符创建的对象P1、P3调用了构析函数。而且删除顺序是按照与创建顺序相反的顺序进行删除,因为较晚创建的对象可能依赖较早创建的对象。最后,缓存区的释放,必须在P1、P3都被销毁之后进行。
还有一点就是在缓存区创建P1、P3时,要提供两个位于缓冲区里面的不同地址,避免两个内存单元重叠。程序中指定了P3相对于P1的偏移量为Test对象的大小。