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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++内存分配与对象构造的分离

發布時間:2023/12/15 c/c++ 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++内存分配与对象构造的分离 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在C++中,我們基本用new(delete)操作符分配(釋放)內存。new操作符為特定類型分配內存,并在新分配的內存中構造該類型的一個對象。new表達式自動運行合適的構造函數來初始化每個動態分配的類類型對象。即new表達式既分配了內存同時也構造了對象。

然而,我們一定會遇到這樣的情況:預先分配用于創建新對象的內存,需要時在預先分配的內存中構造每個對象。即將內存分配與對象構造分開進行,這樣做的理由是:

(1)在內存分配時構造對象很浪費,可能會創建從不使用的對象。

(2)當實際使用預先分配的對象時,被使用的對象很可能要重賦新值。

string* pstr = new string[5];

上面舉了個不合適的例子(當然你應該用vector<string>來代替),毫無疑問被分配的5個string空間是被string默認構造函數初始化了,而且接下來你肯定得對pstr[0...4]重新賦值。所以new操作符這種分配特點會增加運行時開銷。尤其是某些用戶的類類型要求對象分配更快一些,做法通常是:預先分配用于創建新對象的內存,需要時在預先分配的內存中構造每個新對象。

?

一、分配原始內存

C++提供兩種方法分配和釋放未構造的原始內存:

(1)allocator類,它提供可感知類型的內存分配。這個類支持抽象接口,以分配內存并隨后使用該內存保存對象。

2)標準庫中的operator new和operator delete,它們分配和釋放需要大小的原始的,未類型化的內存。

1、allocator類

allocator類是一個模板,它提供類型化的內存分配以及對象構造與撤銷。它支持的操作如下:

allocator類將內存分配和對象構造分開。當allocator對象分配內存的時,它分配適當大小并排列成保存給定類型對象的空間。它分配的內存是未被構造的,allocator的用戶必須分別construct和destroy放置在該內存中的對象。

?

vector的自增長告訴我們:vector為了實現快速內存分配,其實際分配的空間要比當前需要的空間多一些。(實際空間因庫的實現不同而不同),下面為了說明allocator的使用,我們簡陋地實現STL vector中的push_back操作。

template <class T> class VECTOR { public:VECTOR() : elements(NULL), first_free(NULL), end(NULL){}void push_back(const T&); private:static allocator<T> alloc;void reallocate();T *elements;T *first_free;T *end; };

elements:指向數組的第一個元素;first_free:指向最后一個實際元素之后的那個元素;end:指向數組本身之后的那個元素。看下面這張圖可能更清楚一點。

template <class T> void VECTOR<T>::push_back(const T& t) {if (first_free == end) //確認是否有可用空間 {reallocate(); //分配新空間并復制現存元素 }alloc.construct(first_free, t); //構造新元素++first_free; }

下面是reallocate()的簡單實現:

template <class T> void VECTOR<T>::reallocate() {ptrdiff_t size = first_free - elements;ptrdiff_t newCapacity = 2 * max(size, 1);T *newElement = alloc.allocate(newCapacity); //分配兩倍內存 uninitialized_copy(elements, first_free, newElement); //原內存元素拷貝到新內存for (T *p = first_free; p != elements; ) //原內存元素逆序調用析構函數 {alloc.destroy(--p);}if (elements){alloc.deallocate(elements, end - elements); //撤銷原內存空間 }elements = newElement; //調整新內存空間指針指向first_free = elements + size;end = elements + newCapacity; }

說明:本例只做簡單說明。如果你對vector或STL實現感興趣,可以拜讀《STL源碼分析》這本書,我也從這本書學到很多知識。

?

2、operator new函數和operator delete函數

當執行string *sp = new string("initialized");時發生三個步驟:

(1)調用名為operator new的標準庫函數,分配足夠大的原始的未類型化的內存,以保存指定類型的一個對象。

(2)運行該類型的一個構造函數,用指定初始化式構造對象。

(3)返回指向新分配并構造的對象的指針。

當執行delete sp;時發生兩個步驟:

(1)對sp指向的對象運行適當的析構函數。

(2)調用名為operator delete的標準庫函數釋放該對象所用內存。

operator new和operator delete函數有兩個重載版本,每個版本支持相關的new操作:

void *operator new(size_t);

void *operator new[](size_t);

void *operator delete(size_t);

void *operator delete[](size_t);

說明:雖然operator new和operator delete的設計意圖是供new操作符使用,但它們也是標準庫中的函數,可使用它們獲得未構造的內存。舉例如下:

T *newElement = alloc.allocate(newCapacity); //分配兩倍內存T *newElement = static_cast<T*>(operator new[](sizeof(T) * newCapacity));

上面兩條語句是等價的,下面這兩條語句也是等價的。

alloc.deallocate(elements, end - elements); //撤銷原內存空間operator delete[](elements);

說明:allocator類分配類型化的內存,使用時不必計算以字節為單位所需的內存,也避免對operator new的返回值進行強制類型轉換。比直接使用operator new,operator delete更為安全。

?

二、對象構造和撤銷

C++提供了不同方法在原始內存中構造和撤銷對象:

(1)allocator類的成員construct和destroy。

(2)定位new表達式。

(3)直接調用對象的析構函數撤銷對象。撤銷對象并不釋放對象所在的內存。

(4)算法uninitialized_copy和uninitialized_fill構造對象。

?

下面主要介紹定位new表達式(其他情況我們都見過了)。

定位new表達式在已分配的原始內存中初始化一個對象,它不分配內存,接受指向已分配但未構造內存的指針,并在該內存中初始化一個對象。定位new表達式的形式是:

new (place_address) type

new (place_address) type(initializer-list)

其中place_address必須為指針,initializer-list提供了一個可能為空的初始化列表。舉例如下:

alloc.construct(first_free, t); new (first_free) T(t);string *sp = alloc.allocate(2); new (sp) string(b, e);

注意:

(1)定位new表達式初始化一個對象時,可使用任何構造函數,并直接建立對象。allocator類的construct成員總是使用拷貝構造函數。

(2)對于值類型而言,直接構造對象與構造臨時對象并進行拷貝沒有什么區別,性能差別基本沒什么意義。但對某些類而言,使用拷貝構造函數是不可能的(拷貝構造函數可能是私有的等),或應該避免的。這種情況,或許你應該考慮定位new表達式。

轉載于:https://www.cnblogs.com/mengwang024/p/4408841.html

總結

以上是生活随笔為你收集整理的C++内存分配与对象构造的分离的全部內容,希望文章能夠幫你解決所遇到的問題。

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