亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C++ > 正文

總結operator new在C++中的各種寫法

2020-02-24 14:28:29
字體:
來源:轉載
供稿:網友

我們應該都使用過new和delete操作符在堆中應用中釋放內存,這兩個操作符都不能超載,本文是武林技術頻道小編和大家介紹的總結operator new在C++中的各種寫法,希望對你了解這方面內容有幫助!

原生operator new

我們先從原生operator new開始??紤]如下代碼,它用來分配5個int型的空間并返回指向他們的指針[1]:

int* v = static_cast<int*>(::operator new(5 * sizeof(*v)));

當像如上的調用,operator new扮演原生的內存分配角色,類似malloc。上面等價于:

int* v = static_cast<int*>(malloc(5 * sizeof(*v)));

釋放用operator new分配的內存用operator delete:

::operator delete(v);

你愿意永遠用原生new和delete函數嗎?是,只在極少數不用,我在下面的文章中會論證的。為什么用它們而不用原來的可信的malloc和free呢?一個很充分的原因就是你想保持代碼在C++領域的完整性。混合使用new和free(或malloc和delete)是很不可取的(big NO NO)。用new和delete的另一個原因是你可以重載(overload)或重寫(override)這些函數,只要你需要。下面是個例子:

?

void* operator new(size_t sz) throw (std::bad_alloc)
{
??? cerr << "allocating " << sz << " bytesn";
??? void* mem = malloc(sz);
??? if (mem)
??????? return mem;
??? else
??????? throw std::bad_alloc();
}

?

void operator delete(void* ptr) throw()
{
??? cerr << "deallocating at " << ptr << endl;
??? free(ptr);
}


通常,注意到new被用來給內置類型,不包含用戶自定義new函數的類的對象,和任意類型的數組分配空間,使用的都是全局的運算符new。當new被用來為已經被重定義new的類實例化時,用的就是那個類的new函數。

?

下面來看下帶new函數的類。

特定類的operator new
大家有時很好奇"operator new"和"new operator"的區別。前者可以是一個重載的operator new,全局的或者特定類或者原生的operator new。后者是你經常用來分配內存的C++內置的new operator,就像:

Car* mycar = new Car;

C++支持操作符重載,并且我們可以重載的其中一個就是new。

下面是個例子:

?

class Base
{
public:
??? void* operator new(size_t sz)
??? {
??????? cerr << "new " << sz << " bytesn";
??????? return ::operator new(sz);
??? }

?

??? void operator delete(void* p)
??? {
??????? cerr << "deleten";
??????? ::operator delete(p);
??? }
private:
??? int m_data;
};

class Derived : public Base
{
private:
??? int m_derived_data;
??? vector<int> z, y, x, w;
};

int main()
{
??? Base* b = new Base;
??? delete b;

??? Derived* d = new Derived;
??? delete d;
??? return 0;
}


打印結果:
new 4 bytes
delete
new 56 bytes
delete

?

在基類被重載的operator new和operator delete也同樣被子類繼承。如你所見,operator new得到了兩個類的正確大小。注意實際分配內存時使用了::operator new,這是前面所描述過的原生new。在調用前面的兩個冒號很關鍵,是為了避免進行無限遞歸(沒有它函數將一直調用自己下去)。

為什么你要為一個類重載operator new?這里有許多理由。

性能:默認的內存分配算符被設計成通用的。有時你想分配給一個非常特殊的對象,通過自定義分配方式可以明顯地提高內存管理。許多書和文章都討論了這種情況。尤其是"Modern C++ Design"的第4章展示了一個為較小的對象的非常好的設計并實現了自定義的分配算符。

調試 & 統計:完全掌握內存的分配和釋放為調試提供了很好的靈活性,統計信息和性能分析。你可將你的分配算符插入進專門用來探測緩沖區溢出的守衛,通過分配算符和釋放算符(deallocations)的比較來檢測內存泄漏,為統計和性能分析積累各種指標,等等。

個性化:對于非標準的內存分配方式。一個很好的例子是內存池或arenas,它們都使得內存管理變得更簡單。另一個例子是某個對象的完善的垃圾回收系統,可以通過為一個類或整個層面寫你自己的operators new和delete。

研究在C++中new運算符是很有幫助的。分配是分兩步進行:

1.? 首先,用全局operator new指導系統請求原生內存。
2.? 一旦請求內存被分配,一個新的對象就在其中開始構造。

The C++ FAQ給出一個很好的例子,我很愿意在這里這出來:

當你寫下這段代碼:

Foo* p = new Foo();

編譯器會生成類似這種功能的代碼:

?

Foo* p;

?

?// don't catch exceptions thrown by the allocator itself

//不用捕捉分配器自己拋出的異常

?void* raw = operator new(sizeof(Foo));

?// catch any exceptions thrown by the ctor

//捕捉ctor拋出的任何異常

?try {
?? p = new(raw) Foo();? // call the ctor with raw as this 像這樣用raw調用ctor分配內存
?}
?catch (...) {
?? // oops, ctor threw an exception 啊哦,ctor拋出了異常
?? operator delete(raw);
?? throw;? // rethrow the ctor's exception 重新拋出ctor的異常
?}


其中在try中很有趣的一段語法被稱為"placement new",我們馬上就會討論到。為了使討論完整,我們來看下用delete來釋放一個對象時一個相似的情況,它也是分兩步進行:

?

1.首先,將要被刪除對象的析構函數被調用。
2.然后,被對象占用的內存通過全局operator delete函數返還給系統。

所以:
delete p;
等價于[2]:
if (p != NULL) {
? p->~Foo();
? operator delete(p);
}

這時正適合我重復這篇文章第一段提到的,如果一個類有它自己的operator new或 operator delete,這些函數將被調用,而不是調用全局的函數來分配和收回內存。

Placement new
現在,回來我們上面看到樣例代碼中的"placement new"問題。它恰好真的能用在C++代碼中的語法。首先,我想簡單地解釋它如何工作。然后,我們將看到它在什么時候有用。

直接調用 placement new會跳過對象分配的第一步。也就是說我們不會向操作系統請求內存。而是告訴它有一塊內存用來構造對象[3]。下面的代碼表明了這點:

?

int main(int argc, const char* argv[])
{
??? // A "normal" allocation. Asks the OS for memory, so we
??? // don't actually know where this ends up pointing.
??? //一個正常的分配。向操作系統請求內存,所以我們并不知道它指向哪里
??? int* iptr = new int;
??? cerr << "Addr of iptr = " << iptr << endl;

?

??? // Create a buffer large enough to hold an integer, and
??? // note its address.
??? //創建一塊足夠大的緩沖區來保存一個整型,請注意它的地址
??? char mem[sizeof(int)];
??? cerr << "Addr of mem = " << (void*) mem << endl;

??? // Construct the new integer inside the buffer 'mem'.
??? // The address is going to be mem's.
??? //在緩沖區mem中構造新的整型,地址將變成mem的地址
??? int* iptr2 = new (mem) int;
??? cerr << "Addr of iptr2 = " << iptr2 << endl;

??? return 0;
}


在我的機器上輸出如下:

?

Addr of iptr = 0x8679008
Addr of mem = 0xbfdd73d8
Addr of iptr2 = 0xbfdd73d8

如你所見,placement new的結構很簡單。而有趣的問題是,為什么我需要用這種東西?以下顯示了placement new在一些場景確實很有用:

· 自定義非侵入式內存管理。當為一個類重載 operator new 同時也允許自定義內存管理,這里關鍵概念是非侵入式。重載一個類的 operator new需要你改變一個類的源代碼。但假設我們有一個類的代碼不想或者不能更改。我們如何仍能控制它的分配呢? Placement new就是答案。這種用 Placement new達到這個目的的通用編程技術叫做內存池,有時候也叫arenas[4]。

· 在一些程序中,在指定內存區域的分配對象是很必要的。一個例子是共享內存。另一個例子是嵌入式程序或使用內存映射的周邊驅動程序,這些都可以很方便地在它們的“領地”分配對象。

· 許多容器庫預先分配很大一塊內存空間。當一個對象被添加,它們就必須在這里構造,因此就用上了placement new。典型的例子就是標準vector容器。

刪除用placement new 分配的對象

一條C++箴言就是一個用new創建的對象應該用delete來釋放。這個對placement new 同樣適用嗎?不完全是:

?

int main(int argc, const char* argv[])
{
??? char mem[sizeof(int)];
??? int* iptr2 = new (mem) int;

?

??? delete iptr2;?????? // Whoops, segmentation fault! 嗚啊,段錯誤啦!

??? return 0;
}


為了理解上面代碼片段為什么delete iptr2會引起段錯誤(或某種內存異常,這個因操作系統而異),讓我們回想下delete iptr2實際干了什么:

?

1.? First, the destructor of the object that's being deleted is called.

首先,調用將要被刪除的對象的析構函數。

2.? Then, the memory occupied by the object is returned to the OS, represented by the global operator delete function.

然后,這個對象在操作系統中占用的內存用全局operator delete函數收回。

對于用placement new分配的對象,第一步是沒有問題的,但第二步就可疑了。嘗試釋放一段沒有被分配算符實際分配的內存就不對了,但上面的代碼確實這么做了。iptr2指向了一段并沒有用全局operator new分配的棧中的一段位置。然而,delete iptr2將嘗試用全局operator delete來釋放內存。當然會段錯誤啦。

那么我們應該怎么辦?我們應該怎樣正確地刪除iptr2?當然,我們肯定不會認為編譯器怎么會解決怎么翻譯內存,畢竟,我們只是傳了一個指針給placement new,那個指針可能是從棧里拿,從內存池里或者別的地方。所以必須手動根據實際情況來釋放。

事實上,上面的placement new用法只是C++的new指定額外參數的廣義placement new語法的一種特例。它在標準頭文件中定義如下:

?

inline void* operator new(std::size_t, void* __p) throw()
{
??? return __p;
}


C++一個對應的帶有相同參數的delete也被找到,它用來釋放一個對象。它在頭文件中定義如下:

?

?

?


inline void? operator delete? (void*, void*) throw()
{
}


的確,C++運行并不知道怎么釋放一個對象,所以delete函數沒有操作。

?

怎么析構呢?對于一個int,并不真的需要一個析構函數,但假設代碼是這樣的:
char mem[sizeof(Foo)];
Foo* fooptr = new (mem) Foo;

對于某個有意義的類Foo。我們一旦不需要fooptr了,應該怎么析構它呢?我們必須顯式調用它的析構函數:
fooptr->~Foo();
對,顯式調用析構函數在C++中是合法的,并且這也是唯一一種正確的做法[5]。

結論
這是一個復雜的主題,并且這篇文章只起到一個介紹的作用,對C++的多種內存分配方法給出了一種“嘗鮮”。一旦你研究一些細節會發現還有許多有趣的編程技巧(例如,實現一個內存池分配)。這些問題最好是在有上下文的情況下提出,而不是作為一個普通的介紹性文章的一部分。如果你想知道得更多,請查閱下面的資源列表。

資源
· C++ FAQ Lite, especially items 11.14 and 16.9

·? "The C++ Programming Language, 3rd edition" by Bjarne Stroustrup – 10.4.11

· "Effective C++, 3rd edition" by Scott Myers – item 52

·? "Modern C++ Design" by Andrei Alexandrescu – chapter 4

· Several StackOverflow discussions. Start with this one and browse as long as your patience lasts.

?

?

?

我仍會在operator?new前面顯式地寫::(雙冒號),雖然這里并不是必須的。恕我直言,這是一個很好的做法,特別當在重載operator?new的類中,可以避免二義性。

[2]

注意到這里是檢查是否為NULL。這樣做使delete?p?很安全,即使pNULL。

[3]

對傳給placement?new的指針確保有足夠的內存分配給對象,并且確保它們正確地對齊,這都是你的應該做的。

[4]

內存池本身是一個很大且迷人的話題。我并不打算在這里擴展,所以我鼓勵你自己上網找些信息,WIKI如往常一樣是個好地方(good?start)。

[5]

事實上,標準的vector容器用這種方法去析構它保存的數據。

上面就是武林技術頻道小編給大家介紹的總結operator new在C++中的各種寫法,其實在網絡上還有很多這方面知識,但是介紹的都不是很全面,這些小編給大家介紹的都是小編自己操作過的,希望能夠幫助到你們。

?

?

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美尤物巨大精品爽| 国产色视频一区| 国产成人自拍视频在线观看| 国产精品h片在线播放| 在线播放日韩av| 97视频在线观看网址| 日韩在线欧美在线国产在线| 日韩欧美在线免费| 国产精品扒开腿爽爽爽视频| 亚洲免费伊人电影在线观看av| 久久久免费高清电视剧观看| 久久久久久噜噜噜久久久精品| 国产欧美一区二区三区在线| 欧美一区视频在线| 久久久视频免费观看| 7777kkkk成人观看| 日韩美女视频在线观看| 久久精品中文字幕电影| 久久资源免费视频| 久久久久久久999精品视频| 精品国产乱码久久久久久婷婷| 成人网页在线免费观看| 亚洲欧美国产另类| 日本精品久久久久影院| 69视频在线免费观看| 国产精品扒开腿做爽爽爽视频| 日韩在线中文字幕| 91性高湖久久久久久久久_久久99| 国产一区二区三区在线观看网站| 亚洲va欧美va国产综合剧情| 在线看福利67194| 在线看国产精品| 亚洲成人av在线| 欧美性xxxxhd| 亚洲综合成人婷婷小说| 亚洲毛片一区二区| 日韩在线观看免费全集电视剧网站| 亚洲一级黄色av| 国产日韩精品在线| 91精品国产乱码久久久久久久久| 欧美日韩美女视频| 国产精品天天狠天天看| 国产亚洲一级高清| 色无极亚洲影院| 国产日韩欧美综合| 国产亚洲精品综合一区91| 日本电影亚洲天堂| 国产精品久久77777| 亚洲日本中文字幕| 欧美国产日产韩国视频| 欧美电影在线观看网站| 久久人人爽人人爽人人片av高请| 亚洲免费伊人电影在线观看av| 亚洲午夜小视频| 丝袜一区二区三区| 久久国产精品久久久久久久久久| 欧美巨乳在线观看| 亚洲精品黄网在线观看| 日韩亚洲第一页| 国产精品99久久久久久www| 欧美伦理91i| 色综合男人天堂| 久久久欧美一区二区| 亚洲第一中文字幕在线观看| 亚洲精品456在线播放狼人| 日韩精品中文字幕视频在线| 久久久国产精品x99av| 亚洲国产又黄又爽女人高潮的| 综合av色偷偷网| 中文字幕亚洲字幕| 日韩av网站导航| 最新亚洲国产精品| 国产91精品青草社区| 欧美香蕉大胸在线视频观看| 国产精品第100页| 欧美激情国产日韩精品一区18| 蜜臀久久99精品久久久无需会员| 国产在线播放91| 亚洲国产精品小视频| 亚洲欧美国产一本综合首页| 欧美国产亚洲精品久久久8v| 亚洲美女av黄| 中文字幕亚洲国产| 日本免费一区二区三区视频观看| 亚洲网站在线播放| 欧美不卡视频一区发布| 精品国产91久久久久久老师| 欧美视频裸体精品| 亚洲精品国偷自产在线99热| 欧美资源在线观看| 国产精品欧美激情| 国产精品激情自拍| 久久久久久久久久久久久久久久久久av| 国产成人精彩在线视频九色| 69av在线视频| 亚洲美女又黄又爽在线观看| 亚洲第一二三四五区| 亚洲日韩第一页| 日韩激情视频在线| 5566日本婷婷色中文字幕97| 91沈先生在线观看| 色老头一区二区三区在线观看| 久久国产精品久久久久| 精品国产鲁一鲁一区二区张丽| 亚洲免费一在线| 亚洲一区美女视频在线观看免费| 欧洲日本亚洲国产区| 成人动漫网站在线观看| 国内精品久久久久久久久| 国产精品一区二区三区免费视频| 亚洲乱码国产乱码精品精| 欧美极品少妇xxxxⅹ裸体艺术| 久久天天躁狠狠躁夜夜爽蜜月| 日韩av在线一区二区| 亚洲成人久久一区| 伊人伊成久久人综合网小说| 久久青草福利网站| 国产精品一区二区女厕厕| 欧美老肥婆性猛交视频| 91亚洲精品久久久| 欧美一级电影在线| 欧美黑人巨大精品一区二区| 中文字幕在线亚洲| 日韩欧美综合在线视频| 国自在线精品视频| 伊人久久精品视频| 欧美国产日韩一区二区三区| 国产精品自拍网| 国产精品va在线播放我和闺蜜| 欧洲s码亚洲m码精品一区| 久久久电影免费观看完整版| 亚洲xxx大片| 久久久久久久国产| 久久av在线播放| 国内精品视频一区| 欧美在线精品免播放器视频| 亚洲资源在线看| 国产精品国语对白| 色偷偷91综合久久噜噜| 国产精品黄色影片导航在线观看| 欧美超级免费视 在线| 亚洲第一精品夜夜躁人人躁| 亚洲999一在线观看www| 最近中文字幕2019免费| 亚洲激情视频网站| 在线观看欧美日韩国产| 欧美日韩不卡合集视频| 国产成人啪精品视频免费网| 亚洲一区二区久久| 国产成人精品av| 久久久www成人免费精品张筱雨| 欧美专区中文字幕| 国产欧美日韩91| 亚洲成人中文字幕| 亚洲欧洲在线看| 8090理伦午夜在线电影| 久久国产精品久久久久久久久久| 中文字幕精品—区二区| 成人av电影天堂| 国产精品普通话| 亚洲第一av网站| 亚洲人成欧美中文字幕| 欧美日韩国产色视频| 亚洲乱码国产乱码精品精|