常规new和布局new

来源:互联网 发布:在淘宝上开网店程序 编辑:程序博客网 时间:2024/05/01 17:23

通常,new负责在堆(heap)中找到一个能够满足要求的内存块,new操作符还有另外一种变体,称为布局(placement)new操作符,它能够让你指定要使用的位置。
要使用布局new,首先要包含头文件new,它后面需要一个提供地址的参数。话不多说看代码。

// newplace.cpp -- using placement new#include <iostream>#include <new>                                   // for placement newconst int BUF = 512;const int N = 5;char buffer[BUF];                                // chunk of memoryint main( ){    using namespace std;    double *pd1 , *pd2;    int i;    cout << "Calling new and placement new:\n";    pd1 = new double[N];                         // use heap    pd2 = new ( buffer ) double[N];              // use buffer array    for( i = 0; i < N; i++ )        pd2[i] = pd1[i] = 1000 + 20.0 * i;    cout << "Memory addresses:\n" << "  heap: " << pd1        //常规new在堆上分配内存的首地址        << "  static: " << ( void * ) buffer << endl;         //布局new在buffer上分配的首地址    cout << "Memory contents:\n";    for( i = 0; i < N; i++ )    {        cout << pd1[i] << " at " << &pd1[i] << "; ";        cout << pd2[i] << " at " << &pd2[i] << endl;    }    cout << "\nCalling new and placement new a second time:\n";    double *pd3 , *pd4;    pd3 = new double[N];            // find new address    pd4 = new ( buffer ) double[N];  // overwrite old data    for( i = 0; i < N; i++ )        pd4[i] = pd3[i] = 1000 + 40.0 * i;    cout << "Memory contents:\n";    for( i = 0; i < N; i++ )    {        cout << pd3[i] << " at " << &pd3[i] << "; ";        cout << pd4[i] << " at " << &pd4[i] << endl;    }    cout << "\nCalling new and placement new a third time:\n";    delete[] pd1;    pd1 = new double[N];    pd2 = new ( buffer + N * sizeof( double ) ) double[N];    for( i = 0; i < N; i++ )        pd2[i] = pd1[i] = 1000 + 60.0 * i;    cout << "Memory contents:\n";    for( i = 0; i < N; i++ )    {        cout << pd1[i] << " at " << &pd1[i] << "; ";        cout << pd2[i] << " at " << &pd2[i] << endl;    }    delete[] pd1;    delete[] pd3;    // cin.get();    return 0;}

下面是程序的输出(不同电脑运行结果可能不同)
这里写图片描述
我们可以看到
1:布局new确实将p2放在了buffer中,p1则是放在堆中
2:在第二次操作时,常规new查找的是一块新的内存块,布局new分配和以前相同的内存,说明布局new只传递地址,并不跟踪该内存块是否使用过,也不查找未使用的内存块,内存管理的负担交给程序猿
3:是否使用delete来释放内存——对于常规new,delete [ ] pd1;释放最初申请的内存,接下来再次调用new时该内存块可用,程序并没有使用delete来释放布局new分配的内存,这个例子中不能这么做。buffer是静态内存,delete只能用于常规new分配的堆内存,数组buffer位于delete的管辖区之外。当然,如果buffer是用常规new来创建的,也可以用delete释放。

将布局new用于类对象时,情况更复杂。话不多说,先上代码。

#include <iostream>#include <string>#include <new>using namespace std;const int BUF = 512;class JustTesting{private:    string words;    int number;public:    JustTesting( const string & s = "Just Testing" , int n = 0 )    {        words = s; number = n; cout << words << " constructed\n";    }    ~JustTesting( ) { cout << words << " destroyed\n"; }    void Show( ) const { cout << words << ", " << number << endl; }};int main( ){    char * buffer = new char[BUF];       // get a block of memory    JustTesting *pc1 , *pc2;    pc1 = new ( buffer ) JustTesting;      // place object in buffer    pc2 = new JustTesting( "Heap1" , 20 );  // place object on heap    cout << "Memory block addresses:\n" << "buffer: "        << ( void * ) buffer << "    heap: " << pc2 << endl;    cout << "Memory contents:\n";    cout << pc1 << ": ";    pc1->Show( );    cout << pc2 << ": ";    pc2->Show( );    JustTesting *pc3 , *pc4;    // fix placement new location    pc3 = new ( buffer + sizeof( JustTesting ) )   //非优化版pc3 = new (buffer) JustTesting("Bad Idea", 6);        JustTesting( "Better Idea" , 6 );    pc4 = new JustTesting( "Heap2" , 10 );    cout << "Memory contents:\n";    cout << pc3 << ": ";    pc3->Show( );    cout << pc4 << ": ";    pc4->Show( );    delete pc2;           // free Heap1             delete pc4;           // free Heap2    // explicitly destroy placement new objects    pc3->~JustTesting( );  // destroy object pointed to by pc3   非优化版无此行    pc1->~JustTesting( );  // destroy object pointed to by pc1   非优化版无此行    delete[] buffer;     // free buffer    // std::cin.get();    return 0;}

非优化版本的运行结果如图所示:
这里写图片描述
优化版本运行结果如下入所示:
这里写图片描述
对运行结果的差异做出几点说明:
1:程序员想用布局new创建多个对象时,必须提供两个不同的缓冲区地址,否则新对象会覆盖第一个对象的内存空间
2:使用布局new为对象分配内存时,必须确保析构函数被调用,但同时,我们又不能使用 delete pc1;这样的方式来做,因此必须显式地为使用布局new操作符创建的对象调用析构函数,我们删除的时候,应当以创建顺序相反的顺序进行删除,因此晚创建的对象可能依赖于早创建的对象。仅当所有对象都被销毁后,才能释放存储这些对象的缓冲区。

推荐一篇博文,讲得很好。
http://www.cnblogs.com/sunrunner/p/3716134.html

0 0
原创粉丝点击