常规new和布局new

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

// newplace.cpp -- using placement new
#include <iostream>
#include <new>                                   // for placement new
const int BUF = 512;
const int N = 5;
char buffer[BUF];                                // chunk of memory
int 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

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值