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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > c/c++ >内容正文

c/c++

placement new--《C++必知必会》 条款35

發(fā)布時(shí)間:2025/3/15 c/c++ 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 placement new--《C++必知必会》 条款35 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

placement new是重載operator new的一個(gè)標(biāo)準(zhǔn)、全局的版本,它不能被自定義的版本代替(不像普通的operator new和operator delete能夠被替換成用戶自定義的版本)。

placement new原型為:

void * operator new( size_t , void * p) throw(){return n;}

operator new的原型為:

void * operator new( size_t t) { return n;}

首先我們區(qū)分下幾個(gè)容易混淆的關(guān)鍵詞:new、operator new、placement new

new和delete操作符我們應(yīng)該都用過(guò),它們是對(duì)堆中的內(nèi)存進(jìn)行申請(qǐng)和釋放,而這兩個(gè)都是不能被重載的。要實(shí)現(xiàn)不同的內(nèi)存分配行為,需要重載operator new,而不是new和delete。

看如下代碼:

class MyClass {…};

MyClass * p=new MyClass;

這里的new實(shí)際上是執(zhí)行如下3個(gè)過(guò)程:

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

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

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

operator new就像operator+一樣,是可以重載的,但是不能在全局對(duì)原型為void *? operator new(size_t size) 這個(gè)原型進(jìn)行重載,一般只能在類(lèi)中進(jìn)行重載。如果類(lèi)中沒(méi)有重載operator new,那么調(diào)用的就是全局的::operator new來(lái)完成堆的分配。同理,operator new[]、operator delete、operator delete[]也是可以重載的。

placement new是operator new的一個(gè)重載版本,只是我們很少用到它。如果你想在已經(jīng)分配的內(nèi)存中創(chuàng)建一個(gè)對(duì)象,使用new是不行的。也就是說(shuō)placement new允許你在一個(gè)已經(jīng)分配好的內(nèi)存中(棧或堆中)構(gòu)造一個(gè)新的對(duì)象。原型中void*p實(shí)際上就是指向一個(gè)已經(jīng)分配好的內(nèi)存緩沖區(qū)的的首地址。

我們知道使用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)用程序。

使用方法如下:

  • 緩沖區(qū)提前分配
  • 可以使用堆的空間,也可以使用棧的空間,所以分配方式有如下兩種:

    class MyClass {…};
    char *buf=new char[N*sizeof(MyClass)+ sizeof(int) ] ; 或者char buf[N*sizeof(MyClass)+ sizeof(int) ];

  • 對(duì)象的構(gòu)造
  • MyClass * pClass=new(buf) MyClass;

  • 對(duì)象的銷(xiāo)毀
  • 一旦這個(gè)對(duì)象使用完畢,你必須顯式的調(diào)用類(lèi)的析構(gòu)函數(shù)進(jìn)行銷(xiāo)毀對(duì)象。但此時(shí)內(nèi)存空間不會(huì)被釋放,以便其他的對(duì)象的構(gòu)造。

    pClass->~MyClass();

  • 內(nèi)存的釋放
  • 如果緩沖區(qū)在堆中,那么調(diào)用delete[] buf;進(jìn)行內(nèi)存的釋放;如果在棧中,那么在其作用域內(nèi)有效,跳出作用域,內(nèi)存自動(dòng)釋放。

    注意:

    1) 在C++標(biāo)準(zhǔn)中,對(duì)于placement operator new []有如下的說(shuō)明: placement operator new[] needs implementation-defined amount of additional storage to save a size of array. 所以我們必須申請(qǐng)比原始對(duì)象大小多出sizeof(int)個(gè)字節(jié)來(lái)存放對(duì)象的個(gè)數(shù),或者說(shuō)數(shù)組的大小。

    2) 使用方法第二步中的new才是placement new,其實(shí)是沒(méi)有申請(qǐng)內(nèi)存的,只是調(diào)用了構(gòu)造函數(shù),返回一個(gè)指向已經(jīng)分配好的內(nèi)存的一個(gè)指針,所以對(duì)象銷(xiāo)毀的時(shí)候不需要調(diào)用delete釋放空間,但必須調(diào)用析構(gòu)函數(shù)銷(xiāo)毀對(duì)象。

    ?

    new的時(shí)候,其實(shí)做了兩件事,一是:調(diào)用malloc分配所需內(nèi)存,二是:調(diào)用構(gòu)造函數(shù)。

    delete的時(shí)候,也是做了兩件事,一是:調(diào)用析造函數(shù),二是:調(diào)用free釋放內(nèi)存。

    ?

    一個(gè)例子代碼:placement new 在VC6.0不支持,在Qt支持

    class SPort{ public:~SPort(){} }; const int comLoc=0x00400000;//一個(gè)串口空間的位置

    //...void * comAddr = reinterpret_cast<void *>(comLoc);SPort * com1 = new (comAddr) SPort;//在comLoc位置創(chuàng)建對(duì)象//...com1->~SPort();//comLoc變量,離開(kāi)作用域自動(dòng)銷(xiāo)毀/*void * operator new( size_t , void *p) throw()而言,一下代碼SPort * com1 = new (comAddr) SPort;size_t 參數(shù)被初始化為 SPort對(duì)象的大小(以字節(jié)為單位),void * 類(lèi)型的參數(shù)P 則以 comAddr 為處值。*///placement new 也可以在給定空間位置創(chuàng)建對(duì)象數(shù)組const int numComs=4;//...SPort * comPorts = new(comAddr) SPort[numComs];//創(chuàng)建數(shù)組//這些數(shù)組元素必須銷(xiāo)毀int i = numComs;while(i){comPorts[--i].~SPort();}

    第二個(gè)代碼例子:(我沒(méi)懂2018.3.22)

    /*對(duì)象數(shù)組可能出現(xiàn)問(wèn)題的地方在于:當(dāng)數(shù)組被分配時(shí),每一個(gè)元素必須通過(guò)調(diào)用一個(gè)默認(rèn)構(gòu)造函數(shù)而被初始化。下面:考慮一個(gè)簡(jiǎn)單的、固定大小的緩沖區(qū),可以想向這個(gè)緩存區(qū)append(附加)值。 */#define BUFSIZE 1000 std::string *sbuf = new std::string[BUFSIZE]; //調(diào)用默認(rèn)構(gòu)造函數(shù) int size = 0; void append(std::string buf[],int &size , const std::string &val) {buf[size++] = val; //剛才的默認(rèn)構(gòu)造函數(shù)白做了! //這里我沒(méi)懂 } /*如果數(shù)組只有一部分元素被使用,或者元素被立即賦值,那么以上的做法效率低下。更糟糕的是,如果數(shù)組的元素類(lèi)型沒(méi)有默認(rèn)的構(gòu)造函數(shù),我們將的到一個(gè)編譯器錯(cuò)誤。placement new 通常用于解決此類(lèi)緩沖區(qū)問(wèn)題。采用這種方式,緩沖區(qū)占用的存儲(chǔ)區(qū)的分配,可以避免被默認(rèn)的構(gòu)造函數(shù)初始化(如果默認(rèn)構(gòu)造函數(shù)包含初始化代碼) */ const size_t n = sizeof(std::string) * BUFSIZE; std::string * sbuf_ = static_cast<std::string *>(::operator new(n)); //不是太清楚 int size_ = 0; /* 在第一次訪問(wèn)數(shù)組元素時(shí),不能為其賦值,因?yàn)樗€沒(méi)有被初始化。可以使用placement new 通過(guò)賦值構(gòu)造函數(shù)來(lái)初始化元素。 */ void append_(std::string buf[], int & size ,const std::string &val) {new(&buf[size++]) std::string(val) ; } /*通常,使用placement new 也需要做一些清理工作 */ void cleanupBuf(std::string buf[],int size) {while (size)buf[--size].~basic_string(); //qt下測(cè)試是~basic_string //原本buf[--size].~string();::operator delete(buf); } /*這種方式快速而靈活,它并不指望被普通大眾所知曉。這一基本技術(shù)(以更高級(jí)的形式)廣泛的應(yīng)用于大多數(shù)標(biāo)準(zhǔn)容器的實(shí)現(xiàn) */

    ?

    ?

    2

    轉(zhuǎn)載于:https://www.cnblogs.com/azbane/p/8625439.html

    總結(jié)

    以上是生活随笔為你收集整理的placement new--《C++必知必会》 条款35的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。