不要使用vector

2021-07-27 11:02:32 字數 3023 閱讀 2606

做為乙個

stl容器,

vector>

有兩個問題.第一,它不是乙個真正

stl容器,第二,它並不儲存

bool

型別.除此以外,並沒有太多東西與本節題目有關(譯註,還不夠多嗎)

乙個東西不能成為乙個stl容器,只因為會有人說它是乙個(譯註,:( ).乙個東西要成為stl容器,必須滿足所有

列於c++標準23.1節的容器要求.在這些要求中,有這樣一條:如果c是乙個t型別元素容器,並且c支援operator

那麼以下**必須能夠編譯:

t *p = &c[0]; // initialize a t* with the address

// of whatever operator returns

換句話說,如果你使用operator來得到container

中的乙個t物件,你可以對它取位址從而得到乙個指標.

(假設t沒有過載opeartor&.譯註:原句為this assumes that t hasn't perversely overloaded operators.

從意譯)因此,如果vector可能成為容器,那麼,這些**必須編譯通過:

vectorv;

bool *pb = &v[0]; // initialize a bool* with the address of

// what vector::operator returns

但是它不能編譯.不能的原因是vector是乙個偽容器(pseudo-container),它並不儲存真正的bool,而是

打包bool以節省空間.在乙個典型的實現中,每乙個"bool"儲存在"vector"中都是乙個"bit",8-bit的乙個位元組

將儲存8個bool.從內部來看,vector使用了與位域(bitfields)相同的思想來表示需要儲存的bool值.

與bool值相似,位域也只有兩個值,但有它倆之間有乙個重要的不同:可以建立指向真正的bool型的指標,但指

向單獨一位的指標卻非法.

考慮到指向單獨一位的指標非法,這為vector的設計擺出了難題.因為vector::operator的返回值

是t&型別.如果vector儲存真正的bool值,這不成問題.但是因為它沒有,vector::operator

(譯註:原文為()疑誤)不知如何返回一位的引用,並不存在這樣的東西.

為了解決它,vector::operator返回乙個物件,其行為類似於位的引用,也稱為**物件.(僅使用stl,

你並不需要明白什麼是**.它是一項值得了解的c++技術.關於**的資訊,參考more effective c++的item30

還有gamma等人(就是gof)的設計模式一書中proxy章節).深入本質來看,vector可能類似於這樣:

template 

vector; // class to generate proxies for

// references to individual bits

reference operator(size_type n); // operator returns a proxy…}

現在,這些**不能編譯的原因就很明顯了.

vectorv;

bool *pb = &v[0]; // error! the expression on tne right is

// of type vector::reference*,

// not bool*

因為它不能編譯,所以vector不滿足stl容器的需要.vector在標準中,它也滿足了大多數stl容器的需要

,但是它還不夠好.你寫的關stl容器的**越多,會越深刻地認識到這一點.當一天來到時,我保證,當你會寫

出乙個模板,它只在可以取得容器元素的位址時才工作.到那時,你將突然明白容器和幾乎是一容器之間的區別.

也許你想知道為什麼vector存在於標準中,而它並不是乙個容器.答案是與乙個貴族失敗的實驗有關.但讓我們

推遲一下討論,我有乙個更緊迫的問題.如果vector應避免,因為它不是乙個容器,那當需要乙個vector時

應使用什麼?

標準庫提供了兩個代替物,它們滿足幾乎所有需要.第乙個是deque.deque提供幾乎所有vector提供的(唯一值得

注意的是reserve和capacity),並且deque是乙個stl容器,它儲存真正的bool值.當然,deque底層的記憶體不連續.

所以不能傳遞deque中的資料給乙個期望得到bool陣列的c api(參見item 16),但是vector也不能作這一點

因為沒用可移植的方法取得vector中的資料.(item16中的技術不能在vector上編譯.因為這種技術依賴於

能夠取得容器元素的指標.我提到過vector中不儲存bool值吧?)

第二個vector的代替物是bitset.bitset不是乙個stl容器,但它是c++標準庫的一部分.與stl容器不同,它的大小

(元素總數)在編譯期固定.因此,它不支援插入和刪除元素,近一步,因為它不是乙個stl容器,它也不支援iterator.

與vector類似,它使用乙個壓縮的表示法,使得每個值只占用一位.它提供vector的特殊成員函式,還包含

一系列操作位集(collection of bits)的特殊成員函式.如果不在乎沒有迭代器和動態大小,那麼bitset也許正合你意.

現在我們來討論那個貴族的失敗的實驗,正是它將非stl容器的vector留在了標準庫中.我早先提到**物件在c++

程式設計中十分有用.c++標準委員會的成員當然也意識到了,他們決定開發vector做為乙個演示.它說明stl如何

支援包含通過**訪問元素的容器.一但這個例子出現在標準中,而且它說明得很詳細,開發者將有乙個參考,來實現自己

的基於**的容器.

可是,最終他們發現,不可能建立一種基於**的容器,它滿足所有stl容器的需要.因為某種原因,他們失敗了,而開發中

的這個例子留在了標準中.也許有人將探尋vector存在的原因,但現實地說,這不影響什麼.重要的是:vector

不滿足stl容器的需要;你最好不要使用它;deque和bitset是基本能滿足你的需要vector代替品.

盡量不要使用FindWindow

盡量不用 findwindow 最近發現 se6和 se5程序共存時視窗名稱一樣引起的 bug。原因是我們經常使用 findwindow 來獲得視窗控制代碼,然後進行訊息通訊,這樣呼叫簡單,但增加了不同模組之間的依賴性,比如同時有兩個程序時,就可能會找錯視窗。而如果靠人去維護這個視窗名稱,在程式工程...

盡量不要使用可變引數

在某些情況下我們希望函式引數的個數可以根據實際需要來確定,所以c語言中就提供了一種長度不確定的引數,形如 c 語言也繼承了這一語言特性。在採用ansi標準形式時,引數個數可變的函式的原型是 typefuncname typepara1,typepara2,這種形式至少需要乙個普通的形式引數,後面的省...

不要使用kill 9

kill 9 沒有給程序留下善後的機會 1 關閉socket鏈結 2 清理臨時檔案 3 將自己快要給銷毀的訊息通知給子程序 4 重置自己的終止狀態 通常,應該傳送15,等一兩秒鐘,如果沒有效果,傳送2,如果還不行,傳送1.總之,在使用kill 9前,你應該先使用kill 15,給目標程序乙個清理善後...