c++ 標準庫中的allocator是多餘的
我認為c++的allocator是依賴注入的一次失敗的嘗試。
c/c++裡的記憶體分配和釋放是個重要的事情,我同意,在寫library的時候,除了預設使用malloc/free,還應該允許使用者指定使用記憶體分配的函式。用現在的話說,如果library依賴於記憶體分配與釋放,就應該允許使用者注入這種依賴。我看到有些c library是支援這個的,可以在初始化時傳入兩個函式指標,指向記憶體分配和釋放的函式。
問題是,allocator是模板引數,而不是建構函式的引數。這意味著
2. allocator是vector型別的一部分,vector和 vector是兩個型別,不可相互替換。這不僅暴露了實現,還暴露到了型別上,恐怕沒有比這更糟糕的了。
下面舉例說明,
對於1,假設我有乙個任務(假設是parse),需要分配很多小塊記憶體,總容量不超過20m。為了防止記憶體洩露及避免記憶體碎片,我希望在任務開始時,先從系統拿到20m記憶體,供這個任務使用(parse裡分配記憶體只需要改乙個指標,釋放記憶體是空操作),等任務完成後,我一次性釋放這20m記憶體,這樣既高效又安全。然而c++的allocator並不能幫我實現這一點,因為它是全域性的。我不能替換全域性的allocator,因為那會影響其他執行緒。也不能在執行時指定某個vector用哪種allocator,因為型別是編譯時確定的。
對於2,如果我想寫乙個普通的以vector為引數的函式,這不難
void process(vector& records);
由於vector和vector型別不同,process只能接受一種。
但這完全沒道理,我不過想訪問乙個vector,根本不關心它的記憶體是怎麼分配的,卻被什麼鬼東西allocator擋在了門外。
我要麼提供過載:
void process(vector& records);
void process(vector& records);
要麼改寫成模板:
template
void process(vector& records);
//(同理可知,如果在乙個程式裡使用多種allocator,那麼所有涉及標準庫容器的使用者函式都必須改寫為函式模板)
無論哪種"解決辦法"都會導致**膨脹,而且給標準庫的使用者帶來完全不必要的負擔。
更糟糕的是,allocator給程式庫的作者也帶來了不必要的負擔。如果想把process(vector& records)放到某個library中,那麼為了適應不同的allocator,必須把函式定義放在標頭檔案裡(因為這是個函式模板)。明明是針對乙個固定型別(vector of string)的函式,卻不得不寫成函式模板,把實現細節暴露在標頭檔案裡,讓每個使用者都去編譯一遍,這真是完全沒道理。
根據以上的分析,基本上不可能在乙個程式裡混用多種allocator,既然乙個程式只能有一種allocator,那為什麼還要放到每個容器的模板引數裡呢?提供乙個全域性的鉤子不就行了嘛?
相反,shared_ptr就只有乙個模板引數t,而他同樣可以指定allocator----在構造時傳入。
現在看來,vector(以及其他標準庫容器)與其增加乙個alloc模板引數,不如在構造時傳入兩個函式指標,乙個allocate,乙個deallocate,定製的效果也一樣。只不過這麼做會讓標準委員會的人覺得不夠gp,很可能被拍掉。
總而言之,allocator並不能達到精確控制(定製)記憶體分配釋放的目的,雖然它名以上是為此而生的。雖然在歷史上可能有過正面效果(封裝far / near pointer),但現在它無疑就是個累贅。就跟 iostream 的 locale/facet ,auto_ptr 和 valarray 一樣,成為c++標準一直要揹負的歷史包袱。
C 中的標準庫與非標準庫的區別
c 中我們要用到標準輸出,就需要呼叫cout,那麼,cout這條語句怎麼使用呢?例如 include 標頭檔案 int main std cout hello world include int main cout hello world 從這兩個函式來看都沒多大的區別,最後都是輸出 hello w...
C 標準庫中的時間函式
c 語言中的標頭檔案,也就是c語言的中提供時間函式。其中主要是3中資料結構 time t,clock t和struct tm。其實time t和clock t都是乙個整形數,time t記錄的是秒數,而在windows下,clock t儲存的是毫秒數。一 獲取時間 1 clock t clock v...
C 標準類庫中的list
lists將元素按順序儲存在鍊錶中.與 向量 vectors 相比,它允許快速的插入和刪除,但是隨機訪問卻比較慢.stl中 end 指向的總是無效值,取值都用迭代器,用法跟指標差不多。assign 給list賦值 back 返回最後乙個元素 begin 返回指向第乙個元素的迭代器 clear 刪除所...