new(placement new)2

   在实际应用中,遇到这样的情况:已分配好了一块内存,需要在这块内存上面分配一个类对象。这时可以通过强制类型转换,把该内存块强制转换成类对象:
    class A{};
    char *p = new char[100];
    A *pA   = reinterpret_cast<A*>(p);
   但是,这样转换的话,类的构造函数就没有得到调用,类成员变量就没有被初始化。
   这个时候我们可以使用placement new来操作:
   #include   <iostream>
   using namespace std;

   #pragma pack(push, 1)
   class CTest
   {
   public:
       CTest(){m_pTest=new char[100];m_cTest='1';}
       CTest(char *pszStr){m_pTest=new char[100];m_cTest='1';strcpy(m_pTest, pszStr);}
       ~CTest(){delete m_pTest;m_pTest=NULL;}

      void SetString(const char *pszStr){strcpy(m_pTest, pszStr);}
      void Printf() const{cout << m_pTest << endl;};
   private:
       char *m_pTest;
       char m_cTest;
   };
   #pragma pack(pop)

   int main()
   {
       int nLength = sizeof(CTest);
       char szBuf[1000] = {0};
       char *p   = new char[nLength*100+40];

       CTest *pT1 = new (p) CTest("pT1");   // A行,该调用即为placement new
       CTest *pT2 = new (szBuf) CTest("pT2");

       pT1->Printf();
       pT1->~CTest();                                   // 与A行配对使用,释放对象中创建的资源
       pT2->Pritf();
       pT2->~CTest();

       delete []p;

       ::system("pause");

       //_CrtDumpMemoryLeaks();

       return 0;
   }

   何谓placement new? placement new是重载operator new 的一个标准、全局的版本,它不能够被自定义的版本代替(不像普通版本的 operator new 和 operator delete能够被替换)。
   placement new的作用主要就是在一个已存在(分配好的)内存块上面分配一个对象,placement new的使用方法:
   A、创建一个内存块,该内存块可以是栈上的,也可以是堆里面的:
      char *p = new char[1000];
      char szBuf[1000];
   B、在已知内存块上面创建对象:
      CTest pT1 = new (p) CTest("pT1");
      CTest pT2 = new (szBuf) CTest("pT2");
   C、显式调用对象的析构函数释放对象中构造的数据:
      pT1->~CTest();
      pT2->~CTest();
   D、释放内存块(如果需要):
      delete []p;
  
   使用placement new时,需要注意的是,当创建数组对象时,需要注意对象的开始位置:在对象开始位置之前,还会有一个int长度的内存用来保存数组对象的长度:
   int main()
   {
       int nLength = sizeof(CTest);
       char *p   = new char[nLength*5+16];

       CTest *pT1 = new (p) CTest[2];
       CTest *pT3 = new (p+nLength*2+4) CTest[1];
       CTest *pT4 = new (p+nLength*2+4+nLength+4) CTest[1];
       CTest *pT5 = new (p+nLength*2+4+nLength+4+nLength+4) CTest[1];
       CTest *pT2 = pT1+1;

       pT1->SetString("pT1");
       pT2->SetString("pT2");

       pT1->Printf();
       pT1->~CTest();

       pT2->Printf();   
       pT2->~CTest();

       delete p;

       //_CrtDumpMemoryLeaks();

       ::system("pause");
   
       return 0;
   }

   利用debug->windows->memory观察窗口观察下相关指针所指向内存中的数据就可以看得明明白白了。
   如果上面char *p   = new char[nLength*5+16];中的16去掉,直接:
   char *p   = new char[nLength*5];
   CTest *pT1 = new (p) CTest[5];       // 内存操作越界了。
   那么delete []p的时候就会报错了:Heap corruption detected.因为new (p) CTest[5];这个操作所操作的内存超过
p的有效范围了。
posted @ 2011-02-18 15:22  BloodAndBone  Views(376)  Comments(0Edit  收藏  举报