0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

如何讓new操作符不分配內(nèi)存,只構(gòu)造

Linux愛(ài)好者 ? 來(lái)源:Linux愛(ài)好者 ? 作者:Linux愛(ài)好者 ? 2021-01-19 17:01 ? 次閱讀

【導(dǎo)讀】:本文主要介紹如何讓new操作符不分配內(nèi)存,只構(gòu)造。

問(wèn)題

c++中的new操作符通常完成兩個(gè)工作分配內(nèi)存及調(diào)用相應(yīng)的構(gòu)造函數(shù)。

請(qǐng)問(wèn):

如何讓new操作符不分配內(nèi)存,只調(diào)用構(gòu)造函數(shù)?

這樣的用法有什么用?

placement new的含義

placement new可以實(shí)現(xiàn)不分配內(nèi)存,只調(diào)用構(gòu)造函數(shù)。

void*operatornew(size_t,void*p)throw(){returnp;}

placement new的執(zhí)行忽略了size_t參數(shù),只返還第二個(gè)參數(shù)。

其結(jié)果是允許用戶把一個(gè)對(duì)象放到一個(gè)特定的地方,達(dá)到調(diào)用構(gòu)造函數(shù)的效果。

用法如下:

#include #include classTest { public: Test() { std::cout<~Test(); } }

輸出:

Constructor Constructor Destructor

和其他普通的new不同的是,它在括號(hào)里多了另外一個(gè)參數(shù)。比如:

Widget*p=newWidget;---------//ordinarynew pi=new(ptr)int;pi=new(ptr)int;//placementnew

括號(hào)里的參數(shù)ptr是一個(gè)指針,它指向一個(gè)內(nèi)存緩沖器,placement new將在這個(gè)緩沖器上分配一個(gè)對(duì)象。

Placement new的返回值是這 個(gè)被構(gòu)造對(duì)象的地址(比如括號(hào)中的傳遞參數(shù))。

placement new主要適用于:在對(duì)時(shí)間要求非常高的應(yīng)用程序中,因?yàn)檫@些程序分配的時(shí)間是確定 的;長(zhǎng)時(shí)間運(yùn)行而不被打斷的程序;以及執(zhí)行一個(gè)垃圾收集器 (garbage collector)。

new 、operator new 和 placement new 區(qū)別

new :不能被重載,其行為總是一致的。它先調(diào)用operator new分配內(nèi)存,然后調(diào)用構(gòu)造函數(shù)初始化那段內(nèi)存。

operator new:要實(shí)現(xiàn)不同的內(nèi)存分配行為,應(yīng)該重載operator new,而不是new。

delete和operator delete類似。delete首先調(diào)用對(duì)象的析構(gòu)函數(shù),然后調(diào)用operator delete釋放掉所使用的內(nèi)存。

placement new:只是operator new重載的一個(gè)版本。它并不分配內(nèi)存,只是返回指向已經(jīng)分配好的某段內(nèi)存的一個(gè)指針。因此不能刪除它,但需要調(diào)用對(duì)象的析構(gòu)函數(shù)。

new 操作符的執(zhí)行過(guò)程

調(diào)用operator new分配內(nèi)存 ;

調(diào)用構(gòu)造函數(shù)生成類對(duì)象;

返回相應(yīng)指針。

placement new允許你在一個(gè)已經(jīng)分配好的內(nèi)存中(?;蛘叨阎校?gòu)造一個(gè)新的對(duì)象。原型中void*p實(shí)際上就是指向一個(gè)已經(jīng)分配 好的內(nèi)存緩沖區(qū)的的首地址。

Placement new 存在的理由

用Placement new 解決buffer的問(wèn)題

問(wèn)題描述:

用new分配的數(shù)組緩沖時(shí),由于調(diào)用了默認(rèn)構(gòu)造函數(shù),因此執(zhí)行效率上不佳。若沒(méi)有默認(rèn)構(gòu)造函數(shù)則會(huì)發(fā)生編譯時(shí)錯(cuò)誤。如果你想在預(yù)分配的內(nèi)存上創(chuàng)建對(duì)象,用缺省的new操作符是行不通的。要解決這個(gè)問(wèn)題,你可以用placement new構(gòu)造。它允許你構(gòu)造一個(gè)新對(duì)象到預(yù)分配的內(nèi)存上。

增大時(shí)空效率的問(wèn)題

使用new操作符分配內(nèi)存需要在堆中查找足夠大的剩余空間,顯然這個(gè)操作速度是很慢的,而且有可能出現(xiàn)無(wú)法分配內(nèi)存的異常(空間不夠)。

placement new 就可以解決這個(gè)問(wèn)題。我們構(gòu)造對(duì)象都是在一個(gè)預(yù)先準(zhǔn)備好了的內(nèi)存緩沖區(qū)中進(jìn)行,不需要查找內(nèi)存,內(nèi)存分配的時(shí)間是常數(shù);而且不會(huì)出現(xiàn)在程序運(yùn)行中途出現(xiàn)內(nèi) 存不足的異常。所以,placement new非常適合那些對(duì)時(shí)間要求比較高,長(zhǎng)時(shí)間運(yùn)行不希望被打斷的應(yīng)用程序。

使用步驟

在很多情況下,placement new的使用方法和其他普通的new有所不同。這里提供了它的使用步驟。

第一步 緩存提前分配

有三種方式:

為了保證通過(guò)placement new使用的緩存區(qū)的memory alignmen(內(nèi)存隊(duì)列)正確準(zhǔn)備,使用普通的new來(lái)分配它:在堆上進(jìn)行分配

classTask; char*buff=new[sizeof(Task)];//分配內(nèi)存

(請(qǐng)注意auto或者static內(nèi)存并非都正確地為每一個(gè)對(duì)象類型排列,所以,你將不能以placement new使用它們。)

在棧上進(jìn)行分配

classTask; charbuf[N*sizeof(Task)];//分配內(nèi)存

還有一種方式,就是直接通過(guò)地址來(lái)使用。(必須是有意義的地址)

void*buf=reinterpret_cast(0xF00F);

第二步:對(duì)象的分配

在剛才已分配的緩存區(qū)調(diào)用placement new來(lái)構(gòu)造一個(gè)對(duì)象。

Task*ptask=new(buf)Task

第三步:使用

按照普通方式使用分配的對(duì)象:

ptask->memberfunction(); ptask->member; //...

第四步:對(duì)象的析構(gòu)

一旦你使用完這個(gè)對(duì)象,你必須調(diào)用它的析構(gòu)函數(shù)來(lái)毀滅它。按照下面的方式調(diào)用析構(gòu)函數(shù):

ptask->~Task();//調(diào)用外在的析構(gòu)函數(shù)

第五步:釋放

你可以反復(fù)利用緩存并給它分配一個(gè)新的對(duì)象(重復(fù)步驟2,3,4)如果你不打算再次使用這個(gè)緩存,你可以象這樣釋放它:

delete[]buf;

跳過(guò)任何步驟就可能導(dǎo)致運(yùn)行時(shí)間的崩潰,內(nèi)存泄露,以及其它的意想不到的情況。如果你確實(shí)需要使用placement new,請(qǐng)認(rèn)真遵循以上的步驟。

性能對(duì)比

采用placement new和new的方式創(chuàng)建和刪除對(duì)象一萬(wàn)次,統(tǒng)計(jì)時(shí)間,單位是us。

intmain() { { uint64_tstart=GetCurrentTimeInMicroSeconds(); for(uint32_ti=0;i~Test(); } std::cout<

結(jié)果:

placementnew:186 new:1448

結(jié)論:在頻繁構(gòu)造和析構(gòu)對(duì)象的場(chǎng)景中,placement new對(duì)性能有7倍的提升。

責(zé)任編輯:lq

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 緩沖器
    +關(guān)注

    關(guān)注

    6

    文章

    1911

    瀏覽量

    45427
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4284

    瀏覽量

    62325
  • 應(yīng)用程序
    +關(guān)注

    關(guān)注

    37

    文章

    3237

    瀏覽量

    57547

原文標(biāo)題:如何讓 new 操作符只構(gòu)造,不申請(qǐng)內(nèi)存

文章出處:【微信號(hào):LinuxHub,微信公眾號(hào):Linux愛(ài)好者】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    鴻蒙原生應(yīng)用元服務(wù)開(kāi)發(fā)-倉(cāng)頡基礎(chǔ)數(shù)據(jù)類型布爾類型

    let b: Bool = false 布爾類型支持的操作 布爾類型支持的操作符包括:邏輯操作符(邏輯非!,邏輯與 &&,邏輯或 ||)、部分關(guān)系操作符
    發(fā)表于 09-09 09:57

    轉(zhuǎn)載 golang內(nèi)存分配

    . 線程擁有一定的 cache, 可用于無(wú)鎖分配. 同時(shí) Go 對(duì)于 GC 后回收的內(nèi)存頁(yè), 并不是馬上歸還給操作系統(tǒng), 而是會(huì)延遲歸還, 用于滿足未來(lái)的內(nèi)存需求. ?? ? 在 1.
    的頭像 發(fā)表于 09-05 14:12 ?197次閱讀
    轉(zhuǎn)載 golang<b class='flag-5'>內(nèi)存</b><b class='flag-5'>分配</b>

    c語(yǔ)言中從左到右結(jié)合怎么看

    在C語(yǔ)言中,操作符的結(jié)合性(Associativity)是指當(dāng)操作符在表達(dá)式中連續(xù)出現(xiàn)時(shí),它們?nèi)绾闻c操作數(shù)結(jié)合的順序。對(duì)于大多數(shù)二元操作符(即需要兩個(gè)
    的頭像 發(fā)表于 08-20 11:42 ?643次閱讀

    ESP32S3+LVGL創(chuàng)建一個(gè)界面,請(qǐng)問(wèn)能在SPIRAM分配內(nèi)存,IRAM不分配嗎?

    各位前輩好。ESP32S3+LVGL的開(kāi)發(fā)的過(guò)程中發(fā)現(xiàn),創(chuàng)建一個(gè)界面,會(huì)同時(shí)在SPIRAM和IRAM分配相同大小的內(nèi)存。請(qǐng)問(wèn)能在SPIRAM分配內(nèi)
    發(fā)表于 06-06 07:45

    Linux內(nèi)核內(nèi)存管理之內(nèi)核非連續(xù)物理內(nèi)存分配

    我們已經(jīng)知道,最好將虛擬地址映射到連續(xù)頁(yè)幀,從而更好地利用緩存并實(shí)現(xiàn)更低的平均內(nèi)存訪問(wèn)時(shí)間。然而,如果對(duì)內(nèi)存區(qū)域的請(qǐng)求并不頻繁,那么考慮基于通過(guò)連續(xù)線性地址訪問(wèn)非連續(xù)頁(yè)幀的分配方案是有意義的。該模式
    的頭像 發(fā)表于 02-23 09:44 ?843次閱讀
    Linux內(nèi)核<b class='flag-5'>內(nèi)存</b>管理之內(nèi)核非連續(xù)物理<b class='flag-5'>內(nèi)存</b><b class='flag-5'>分配</b>

    Linux內(nèi)核內(nèi)存管理之ZONE內(nèi)存分配

    內(nèi)核中使用ZONE分配器滿足內(nèi)存分配請(qǐng)求。該分配器必須具有足夠的空閑頁(yè)幀,以便滿足各種內(nèi)存大小請(qǐng)求。
    的頭像 發(fā)表于 02-21 09:29 ?846次閱讀

    FreeRTOS內(nèi)存機(jī)制詳解

    FreeRTOS是一種實(shí)時(shí)操作系統(tǒng),它提供了多種內(nèi)存分配方式,包括動(dòng)態(tài)內(nèi)存分配和靜態(tài)內(nèi)存
    的頭像 發(fā)表于 12-31 16:49 ?2464次閱讀
    FreeRTOS<b class='flag-5'>內(nèi)存</b>機(jī)制詳解

    “+”操作符的使用技巧

    這篇寫個(gè)平時(shí)易被忽略的小知識(shí)點(diǎn),一元 + 操作符的使用技巧。
    的頭像 發(fā)表于 12-28 13:27 ?493次閱讀

    oracle中拼接字符串函數(shù)

    , string2) 其中,string1 和 string2 是需要連接的字符串參數(shù)。 除了 CONCAT 函數(shù),Oracle 還提供了一些其他的字符串拼接函數(shù)和操作符,這些函數(shù)和操作符可以根據(jù)具體的要求和情況來(lái)
    的頭像 發(fā)表于 12-06 09:49 ?2748次閱讀

    sql的where條件多個(gè)and順序

    在SQL中,WHERE子句用于過(guò)濾查詢結(jié)果以提供符合特定條件的記錄。當(dāng)有多個(gè)AND操作符時(shí),WHERE子句的順序并不會(huì)影響查詢結(jié)果,但是正確的AND操作符順序可以提高查詢的可讀性和性能。 首先,我們
    的頭像 發(fā)表于 11-23 11:33 ?3718次閱讀

    sql怎么在where條件判斷

    在SQL中,WHERE條件用于篩選符合特定條件的記錄。它提供了一種在查詢中過(guò)濾數(shù)據(jù)的方法,使您能夠根據(jù)所需的特定條件對(duì)查詢結(jié)果進(jìn)行更精確的控制。 在WHERE子句中,您可以使用各種操作符和函數(shù)來(lái)構(gòu)建
    的頭像 發(fā)表于 11-23 11:30 ?1821次閱讀

    sql語(yǔ)句where條件查詢

    的細(xì)節(jié),包括使用的操作符、條件的組合、多張表的查詢、條件的性能優(yōu)化等方面。 首先,讓我們了解一下WHERE子句中常用的操作符。在SQL中,常用的操作符包括: 比較操作符: 等于(=):
    的頭像 發(fā)表于 11-23 11:28 ?1103次閱讀

    數(shù)據(jù)庫(kù)having的用法

    進(jìn)行篩選,并且它可以使用的操作符包括比較操作符(如等于、大于、小于等)、邏輯操作符(如AND、OR、NOT)以及數(shù)學(xué)運(yùn)算 (如加、減、乘、除)。 在介紹HAVING的用法之前,我們先
    的頭像 發(fā)表于 11-23 11:21 ?2544次閱讀

    如何使用自增自減運(yùn)算提高效率

    使用自增自減運(yùn)算提高效率 在使用到加一和減一操作時(shí)盡量使用增量和減量操作符,因?yàn)樵隽?b class='flag-5'>符語(yǔ)句比賦值語(yǔ)句更快,原因在于對(duì)大多數(shù)CPU來(lái)說(shuō),對(duì)內(nèi)存字的增、減量
    的頭像 發(fā)表于 11-21 11:29 ?496次閱讀

    malloc 申請(qǐng)內(nèi)存的兩種方式

    我們知道m(xù)alloc() 并不是系統(tǒng)調(diào)用,也不是運(yùn)算,而是 C 庫(kù)里的函數(shù),用于動(dòng)態(tài)分配內(nèi)存。 malloc 申請(qǐng)內(nèi)存的時(shí)候,會(huì)有兩種方式向操作
    的頭像 發(fā)表于 11-13 11:42 ?2561次閱讀
    malloc 申請(qǐng)<b class='flag-5'>內(nèi)存</b>的兩種方式