posts - 195, comments - 34, trackbacks - 0, articles - 1

          C++ placement new 用法舉例zz

          Posted on 2010-04-20 17:15 小強(qiáng)摩羯座 閱讀(3808) 評(píng)論(0)  編輯  收藏 所屬分類: C++ &VC
          C++ placement new 用法舉例zz
          2009-12-17 16:16

          在處理內(nèi)存分配的時(shí)候,C++程序員會(huì)用new操作符(operator new)來分配內(nèi)存,并用delete操作符(operator delete)來釋放內(nèi)存。這是一個(gè)new操作符的例子。

          class CTest
          {
               
          /* 成員函數(shù)和成員數(shù)據(jù) */
          };

          // . . . 代碼

          //
          分配一個(gè)對(duì)象
          CTest * pTest = new Test;
          // 分配一個(gè)有十個(gè)對(duì)象的數(shù)組 (CTest 要有缺省構(gòu)造函數(shù)(default constuctor)
          CTest * p10Tests = new Test[ 10];

          雖然這種寫法在大多數(shù)時(shí)候都工作得很好,但還是有些情況下使用new是很煩人的,比如當(dāng)你想重新分配一個(gè)數(shù)組或者當(dāng)你想在預(yù)分配的內(nèi)存上構(gòu)造一個(gè)對(duì)象的時(shí)候。

          比如第一種情況,重新分配一個(gè)數(shù)組效率是很低的:

          // 分配一個(gè)有10個(gè)對(duì)象的數(shù)組
          CTest * pTests = new Test[ 10];
          // . . .
          //
          假設(shè)現(xiàn)在我們需要11個(gè)對(duì)象
          CTest * pNewTests = new Test[ 11];
          // . . . 我們必須把原來的對(duì)象拷貝到新分配的內(nèi)存中
          for ( int i = 0; i < 10; i++)
               pNewTests[ i] = pTests[ i];
          delete pTests;
          pTests = pNewTests;

          如果你想在預(yù)分配的內(nèi)存上創(chuàng)建對(duì)象,用缺省的new操作符是行不通的。要解決這個(gè)問題,你可以用placement new構(gòu)造。它允許你構(gòu)造一個(gè)新對(duì)象到預(yù)分配的內(nèi)存上:

          // buffer 是一個(gè)void指針 (void *)
          //
          用方括號(hào)[] 括起來的部分是可選的
          [CYourClass * pValue = ] new( buffer) CYourClass[( parameters)];

          下面是一些例子:

          #include <new>

          class CTest
          {
          public:
               CTest()
               {}
               CTest( int)
               {}
              
          /* 代碼*/
          };

          int main(int argc, char* argv[])
          {

               //
          由于這個(gè)例子的目的,我們不考慮內(nèi)存對(duì)齊問題
               char strBuff[ sizeof( CTest) * 10 + 100];
               CTest * pBuffer = ( CTest *)strBuff;

              
          // 缺省構(gòu)造
               CTest * pFirst = new(pBuffer) CTest;

              
          // 缺省構(gòu)造
               CTest * pSecond = new(pBuffer + 1) CTest;
              
              
          // 帶參數(shù)的構(gòu)造;
               //
          不理會(huì)返回的指針
               new(pBuffer + 2) CTest( 5);

              
          // 帶參數(shù)的構(gòu)造
               CTest * pFourth = new( pBuffer + 3) CTest( 10);

              
          // 缺省構(gòu)造
               CTest * pFifth = new(pBuffer + 4) CTest();

              
          // 構(gòu)造多個(gè)元素(缺省構(gòu)造)
               CTest * pMultipleElements = new(pBuffer + 5) CTest[ 5];
               return 0;
          }

          當(dāng)你有自己的內(nèi)存緩沖區(qū)或者在你實(shí)現(xiàn)自己的內(nèi)存分配策略的時(shí)候,placement new會(huì)很有用。事實(shí)上在STL中廣泛使用了placement new來給容器分配內(nèi)存;每個(gè)容器類都有一個(gè)模版參數(shù)說明了構(gòu)造/析構(gòu)對(duì)象時(shí)所用的分配器(allocator)。

          在使用placement new的時(shí)候,你要記住以下幾點(diǎn):

          • 加上頭文件#include <new>
          • 你可以用placement new構(gòu)造一個(gè)數(shù)組中的元素。
          • 要析構(gòu)一個(gè)用placement new分配的對(duì)象,你應(yīng)該手工調(diào)用析構(gòu)函數(shù)(并不存在一個(gè)“placement delete”)。它的語法如下:

          pFirst->~CTest();
          pSecond->~CTest();

          前段事件,我問過關(guān)于placement new的問題,一位仁兄講了一些道理,他說道:

          ::棧上的對(duì)象(注意,是類對(duì)象,char類型就無需了,后面還會(huì)提到)保證放在對(duì)齊地址上. 

          但是,個(gè)人實(shí)驗(yàn)了一下,發(fā)現(xiàn)并不是這樣

          例如:
          int main()
          {
          char c1 = 'A' ;
          char c2 = 'B' ;
          char c3 = 'C' ;
          char c4 = 'D' ;
          char c5 = 'E' ;

          //-------- 驗(yàn)證這四個(gè)地址是否是 4 的倍數(shù) --------------//
          if ( ((int)(&c1)) % 4 == 0 )
          cout << "c1:Yes" << endl ;

          if ( ((int)(&c2)) % 4 == 0 )
          cout << "c2:Yes" << endl ;

          if ( ((int)(&c3)) % 4 == 0 )
          cout << "c3:Yes" << endl ;

          if ( ((int)(&c4)) % 4 == 0 )
          cout << "c4:Yes" << endl ;

          if ( ((int)(&c5)) % 4 == 0 )
          cout << "c5:Yes" << endl ;

          cout << (int)(&c1) << endl // 輸出四個(gè)字符所在的地址(輸出結(jié)果都是 4 的倍數(shù))
           << (int)(&c2) << endl 
           << (int)(&c3) << endl 
           << (int)(&c4) << endl 
           << (int)(&c5) << endl ;
          }
          -----------------------------
          上面的執(zhí)行結(jié)果在VC下運(yùn)行都是 4 的倍數(shù)
          --------------

          --> 問題1:連棧上分配的空間地址都是 4 的倍數(shù),那就說明系統(tǒng)分配的空間都是 4 的倍數(shù)吧???

          --> 問題2:如果萬一,如果放一個(gè)對(duì)象的地址不是4的倍數(shù),那么會(huì)出現(xiàn)什么情況??可以給簡單說一下嗎?

          --> 問題3:地址對(duì)齊的通用性???
             -------------
             程序1:
          Class C1
          {
          int i ;
          char c ;
          } ;
          cout << sizeof(C1) << endl ;// 輸出結(jié)果: 8 (是 4 的倍數(shù))
             程序2:
          class C2
          {
          char c1 ;
          char c2 ;
          } ;
          cout << sizeof(C2) << endl ;// 輸出結(jié)果:2 ( 上一個(gè)中char類型也給了4個(gè)字節(jié),怎么這個(gè)地方都給了一個(gè)字節(jié)??)
          --> 問題4:由上面的程序2 引出下面的程序
          class C2// sizeof(C2) =2 ,在VC實(shí)驗(yàn)下的結(jié)果,不是 4
          {
          char c1 ;
          char c2 ;
          } ;
          //----------用placement new方法建立對(duì)象----------------
          void *ptr = operator new(100) ;// 分配內(nèi)存
          C2 *POINTER = (C2*)ptr ;// 類型轉(zhuǎn)換
          String *str1 = new (POINTER) C2() ;// 建立一C2對(duì)象
          String *str2 = new (POINTER+1) C2() ;// 再建立一個(gè)對(duì)象
          String *str3 = new (POINTER+2) C2() ;// 再建立一個(gè)對(duì)象

          cout << (int)(str1) << endl// 結(jié)果:3608720(  是4的倍數(shù))
                << (int)(str2) << endl // 結(jié)果:3608722(不是4的倍數(shù))!!
                               << (int)(str3) << endl ;// 結(jié)果:3608724(不是4的倍數(shù))!!


          主站蜘蛛池模板: 科尔| 南岸区| 安平县| 咸宁市| 西乌珠穆沁旗| 星座| 阿尔山市| 澄迈县| 修文县| 浦北县| 寿光市| 丹阳市| 永春县| 金湖县| 藁城市| 兴宁市| 响水县| 合江县| 永春县| 萨嘎县| 神池县| 江陵县| 新闻| 宁乡县| 盐边县| 大厂| 清丰县| 涟源市| 南和县| 汝州市| 康保县| 海盐县| 岳普湖县| 蒙阴县| 西昌市| 武胜县| 永胜县| 凤山县| 招远市| 潜江市| 宁都县|