日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

new的三种形态

發布時間:2024/4/14 编程问答 64 豆豆
生活随笔 收集整理的這篇文章主要介紹了 new的三种形态 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

C++語言一直被認為是復雜編程語言中的杰出代表之一,不僅僅是因為其繁縟的語法規則,還因為其晦澀的術語。下面要講的就是你的老熟人—new:

它是一個內存管理的操作符,能夠從堆中劃分一塊區域,自動調用構造函數,動態地創建某種特定類型的數據,最后返回該區域的指針。該數據使用完后,應調用delete運算符,釋放動態申請的這塊內存。

如果這就是你對new的所有認識,那么我不得不說,你依舊被new的和善外表所蒙蔽著??此坪唵蔚膎ew其實有著三種不同的外衣。

是的,你沒有看錯,也不用感到驚奇,一個簡單的new確實有三種不同的形態,它扮演著三種不同的角色,如下所示:

?

  • new?operator ?
  • operator?new ?
  • placement?new?
  • ?

    下面的代碼片段展示的是我們印象中熟悉的那個new:

  • string?*pStr?=?new?string("Memory?Management"); ?
  • int?*pInt?=?new?int(2011);?
  • ?

    這里所使用的new是它的第一種形態new operator。它與sizeof有幾分類似,它是語言內建的,不能重載,也不能改變其行為,無論何時何地它所做的有且只有以下三件事,如圖3-2所示。

    ?
    圖3-2 new operator所完成的三件事


    所以當寫出“string *pStr = new string("Memory Management");”代碼時,它其實做的就是以下幾件事:

  • //為string對象分配raw內存 ?
  • void?*memory?=?operator?new(?sizeof(string)?); ?
  • //調用構造函數,初始化內存中的對象 ?
  • call?string::string()on?memory; ?
  • //獲得對象指針 ?
  • string?*pStr?=?static_cast<string*>(memory); ?
  • 當然,對于內置類型,第二步是被忽略的,即: ?
  • //為int分配raw內存 ?
  • void?*memory?=?operator?new(?sizeof(int)?); ?
  • //獲得對象指針 ?
  • int?*pInt?=?static_cast<int*>(memory);?
  • 其實new operator背后還藏著一個秘密,即它在執行過程中,與其余的兩種形態都發生了密切的關系:第一步的內存申請是通過operator new完成的;而在第二步中,關于調用什么構造函數,則由new的另外一種形態placement new來決定的。

    對于new的第二種形態—內存申請中所調用的operator new,它只是一個長著“明星臉”的普通運算符,具有和加減乘除操作符一樣的地位,因此它也是可以重載的。

    operator new在默認情況下首先會調用分配內存的代碼,嘗試從堆上得到一段空間,同時它對事情的結果做了最充分的準備:如果成功則直接返回;否則,就轉而去調用一個new_hander,然后繼續重復前面過程,直到異常拋出為止。所以如果operator new要返回,必須滿足以下條件之一:

    內存成功分配。

    拋出bad_alloc異常。

    通常,operator new函數通過以下方式進行聲明:

  • void*?operator?new(size_t?size);?
  • ?

    注意,這個函數的返回值類型是void*,因為這個函數返回的是一個未經處理的指針,是一塊未初始化的內存,它像極了C庫中的malloc函數。如果你對這個過程不滿意,那么可以通過重載operator new來進行必要的干預。例如:

  • class?A ?
  • { ?
  • public: ?
  • ?????A(int?a); ?
  • ?????~A(); ?
  • ?????void*?operator?new(size_t?size); ?
  • ?... ?
  • }; ?
  • void*?A::operator?new(size_t?size) ?
  • { ?
  • ?cout<<"Our?operator?new..."); ?
  • ?return?::operator?new(size); ?
  • }?
  • 這里的operator new調用了全局的new來進行內存分配(::operator new(size))。當然這里的全局new也是可以重載的,但是在全局空間中重載void * operator new(size_t size)函數將會改變所有默認的operator new的行為方式,所以必須十二分的注意。還有一點需要注意的是,正像new與delete一一對應一樣,operator new和operator delete也是一一對應的;如果重載了operator new,那么也得重載對應的operator delete。

    最后,要介紹的是new的第三種形態—placement new。正如前面所說的那樣,placement new是用來實現定位構造的,可以通過它來選擇合適的構造函數。雖然通常情況下,構造函數是由編譯器自動調用的,但是不排除你有時確實想直接手動調用,比如對未初始化的內存進行處理,獲取想要的對象,此時就得求助于一個叫做placement new的特殊的operator new了:

  • #include?<new>?
  • #include?"ClassA.h" ?
  • int?main() ?
  • { ?
  • ?????void?*s?=?operator?new(sizeof(A)); ?
  • ?A*?p?=?(A*)s; ?
  • ?new(p)?A(2011);??//p->A::A(2011); ?
  • ?...?//?processing?code ?
  • ?????return?0; ?
  • }?
  • ?

    placement new是標準C++庫的一部分,被聲明在了頭文件中,所以只有包含了這個文件,我們才能使用它。它在文件中的函數定義很簡單,如下所示:

  • #ifndef?__PLACEMENT_NEW_INLINE ?
  • #define?__PLACEMENT_NEW_INLINE ?
  • inline?void?*__CRTDECL?operator?new(size_t,?void?*_Where)?_THROW0() ?
  • {???//?construct?array?with?placement?at?_Where ?
  • ????return?(_Where); ?
  • } ?
  • ?
  • inline?void?__CRTDECL?operator?delete(void?*,?void?*)?_THROW0() ?
  • {???//?delete?if?placement?new?fails ?
  • } ?
  • #endif?/*?__PLACEMENT_NEW_INLINE?*/?
  • 這就是placement new需要完成的事。細心的你可能會發現,placement new的定義與operator new聲明之間的區別:placement new的定義多一個void*參數。使用它有一個前提,就是已經獲得了指向內存的指針,因為只有這樣我們才知道該把placement new初始化完成的對象放在哪里。

    在使用placement new的過程中,我們看到的卻是"new(p) A(2011)"這樣奇怪的調用形式,它在特定的內存地址上用特定的構造函數實現了構造一個對象的功能,A(2011)就是對構造函數A(int a)的顯式調用。當然,如果顯式地調用placement new,那么也得本著負責任的態度顯式地調用與之對應的placement delete:p->~A();。這部分工作本來可以由編譯器獨自完成的:在使用new operator的時候,編譯器會自動生成調用placement new的代碼,相應的,在調用delete operator時同樣會生成調用析構函數的代碼。所以,除非特別必要,不要直接使用placement new。但是要清楚,它是new operator的一個不可或缺的步驟。當默認的new operator對內存的管理不能滿足我們的需要,希望自己手動管理內存時,placement new就變得有用了。就像STL中的allocator一樣,它借助placement new來實現更靈活有效的內存管理。

    最后,總結一下:

    如果是在堆上建立對象,那么應該使用 new operator,它會為你提供最為周全的服務。

    如果僅僅是分配內存,那么應該調用operator new,但初始化不在它的工作職責之內。如果你對默認的內存分配過程不滿意,想單獨定制,重載operator new 是不二選擇。

    如果想在一塊已經獲得的內存里建立一個對象,那就應該用placement new。但是通常情況下不建議使用,除非是在某些對時間要求非常高的應用中,因為相對于其他兩個步驟,選擇合適的構造函數完成對象初始化是一個時間相對較長的過程。

    請記住:

    不要自信地認為自己對new很熟悉,要正確區分new所具有的三種不同形態,并能在合適的情形下選擇合適的形態,以滿足特定需求。

    總結

    以上是生活随笔為你收集整理的new的三种形态的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。