SGI STL空間配置器(STL原始碼剖析)

2021-05-22 16:13:46 字數 4394 閱讀 2662

空間配置器的標準介面(根據

stl規範)

allocator::value_type

allocator::pointer

allocator::const_pointer

allocator::reference

allocator::const_reference

allocator::size_type

allocator::difference_type

allocator::rebind //

乙個巢狀的類模板

allocator::allocator()

allocator::allocator(const allocator&)

templateallocator::allocator(const allocator&)

//泛化的拷貝建構函式

allocator::~allocator()

pointer allocator::

address

(reference x) const

//返回某個物件的位址

.  a.address(x)

等於&x

const_pointer allocator::address(const_reference x) const

//同上

. 返回乙個

const

物件的位址

pointer allocator::

allocate

(size_type n, const void* = 0 )

//分配空間

, 足以儲存n個

t物件void allocator::

deallocate

(pointer p, size_type n)

//釋放空間

size_type allocator::

max_size

() const

//返回可成功分配的最大量

void allocator::

construct

(pointer p , const t& x)

//負責構造

相當於new ((const void*)p) t(x)

void allocator::

destroy

(pointer p)

//負責析構

相當於p->~t()

——————————————————————————————————————

sgi stl

的配置器與眾不同,

名稱是alloc

而不是allocator

,而且不接受任何引數。

vector> iv;   //in vc or cb

vectoriv;                //in gcc

但是通常都是使用預設的空間配置器,而

sgi stl

已經為每乙個容器都指定了預設的空間配置器。所以使用的時候無太大區別。

template

class vector;       //

預設使用

alloc

————————————————————————————————————————

sgi空間配置器分析:

c++的

new操作符和

delete

操作符進行記憶體配置時,

new:先配置記憶體,然後構造物件。

delete

:先析構物件,然後釋放記憶體。

sgi stl

將記憶體配置、釋放記憶體與構造、析構分開。前者由

中的allocate()

和deallocate()

負責,後者由

中的construct()

和destroy()

負責。這兩個標頭檔案包含於

中(stl

標準規定,配置器定義在

memory

中)。同時

還包含了乙個檔案

,定義了一些全域性函式用來填充、複製大塊記憶體資料。 1.

構造和析構。

構造:template

inline void construct(t1 *p, const t2& value)

template

__destroy_aux(forwarditerator first, forwarditerator last, __ture_type) {}

同時這個析構函式對

char*

和wchar_t*

有特化版本:將不呼叫他們的析構函式。(這是沒有必要呼叫析構函式的例子麼?)

2. 空間的配置和釋放:

std::alloc

std::alloc

為了效率,設計了雙層級配置器,第一級直接使用c的

malloc()

和free()

。第二級則視配置區塊的大小選擇配置器,如果區塊大,則直接呼叫第一級,如果區塊過小,則採用

memory pool

整理的方法。

sgi將其簡單的包裝了乙個介面,

******_alloc

類。使其符合

stl規格。而在使用的時候全部使用的

******_alloc

介面(預設使用)。

第一級配置器: 呼叫

malloc()

和realloc()

,如果配置不成功,則呼叫

oom_malloc(), oom_realloc()(ps

:oom= out of memory

)。在oom_***

的處理時,通過不斷呼叫

「記憶體不足處理例程

」,期望在某次呼叫之後能夠分配到。設計

「記憶體不足處理例程

」是客戶端的責任。(

effective c++

對new-handler

的行為有乙個條款,還沒認真看)

第二級配置器:

由於太多小額的區塊會造成記憶體的碎片,同時也會帶來額外的負擔,因此通過第二級配置器的分配,適當的將小額記憶體分配出去。當區塊小(

<128bytes

)的時候,採用記憶體池管理。第二級配置器維護了16個

free-lists

,各自管理從

8~128bytes

的小額區塊,每乙個區塊以

8bytes

遞增(將每乙個小額的區塊需求上調至

8的倍數,以便管理)。每一次需要時候就將適當的記憶體從

free-lists

中間拔出來。客戶釋放後就**到

free-lists

中。當需要的

free-lists

中沒有可用的區塊的時候,呼叫

refill()

函式為free-lists

填充新的空間(取自記憶體池,用

chunk_alloc()

函式)。記憶體池的處理十分複雜,看的一頭霧水。

sgi配置器使用方法:

template

class vector;

其中第二個

template

引數接受預設的

alloc

,可以是第一級配置器也可以是第二級配置器。

sgi stl

已經把它設定為第二級配置器。

3. 記憶體基本處理工具

在標頭檔案

中,定義了

3個全域性函式,

uninitialized_copy(),uninitialized_fill(),uninitialized_fill_n().

看到這些名字應該就知道它們是什麼作用了,它們負責在已分配好的空間進行構造。這三個函式都具有

」commit or rollback」

語意。要麼構造出所有元素,要麼不構造任何東西。

在具體的實現中,這三個函式也用到了

traits

技法,通過

traits

萃取出元素的特性,如果是

pod(

plain old data

)型別,說明其擁有

trivial ctor/ dtor/ copy/ assignment

函式,因此可以使用

copy()

、fill()

、fill_n()

等演算法,如果不是

pod型別就只能夠迴圈呼叫

construct()

函式了。這裡用到的也是函式過載的方法,和上面

destroy

用到的方法是一樣的。

注意:在

unitialized_copy()

實現的時候,針對

char*

和wchar_t*

兩種型別,可以採用最有效率的

memmove()

來複製,因此需要兩份特化版本。

SGI STL空間配置器和記憶體池

最近在看侯捷老師的 stl原始碼剖析 非常感嘆其中空間配置器實現的巧妙和細緻,對效率真正是錙銖必較。一般我們所習慣的記憶體配置和釋放是通過new和delete來完成的,而new運算包含了兩個階段 1.呼叫 operator new配置記憶體 2.呼叫建構函式 foo 構造物件。delete運算也包含...

STL 空間配置器

stl有6大元件 容器 演算法 迭代器 仿函式 配接器 分配器。它們之間的密切關係是stl的精髓所在,容器用來存放資料,而容器存在的前提是要有分配器給它分配記憶體,接下來需要實現演算法,迭代器便作為演算法來對容器資料操作的橋梁,演算法可以使用仿函式完成不同的策略變化,配接器可修飾或套接仿函式。說了麼...

STL 空間配置器

stl空間配置器的底層原理 維護了乙個狹義的記憶體池,並且用乙個自由鍊錶來維護該記憶體池。該自由鍊錶比較類似於雜湊的開鏈法的儲存結構。源 pragma once using namespace std define throw bad alloc cerr out of memory endl ex...