第二部分 vector和容器
第十三條:vector和string優先於動態分配的數組
當你決定用new來分配內存時,將承擔以下責任:
n 你必須確保以後會有人調用delete來刪除所分配的內存,否則將導致資源泄露。
n 你必須確保調用了正確的delete形式。比如單個對象調用delete;分配了數組,則調用delete[]。
n 你必須確保只delete了一次。如果一次分配被多次delete,結果也是不確定的。
如果使用vector和string,則可以減少以上的擔憂。
如果你使用的string是以引用計數來實現的,而又在多線程的環境中,可以考慮以下幾種做法:
n 檢查庫實現,看看是否可以禁止引用計數。這種方法不可移植。
n 尋找或開發一個不適用引用計數的string實現。
n 考慮使用vector<char>而不是string,會丟失使用string的成員函數的機會,但可以通過stl算法實現。
第十四條使用reserve來避免不必要的分配。
Vector和的string的自動增長是這樣實現的:
n 當容器容量不足時,分配一塊大小爲當前容量+max(當前容量,新增容量) 的新內存。大多數時候,都是每次以2的倍數增長,即容量需要擴張時,它們的容量加倍。
n 把容器的所有元素從舊的內存複製到新的內存。
n 析構掉舊內存中的對象
n 釋放舊內存
因此,容器的自動增長是會很耗時的。使用reserve能避免容器不必要的重複分配。主要有兩種方式:
n 若能確切知道或大概預計容器中最終會有多少元素,則可以使用reserve。
n 先預留足夠大的空間,然後,當把所有數據都加入以後,去除多餘的容量。可以考慮使用“swap技巧“(見17條)。
第十五條 注意string實現的多樣性
幾乎每個string實現都包含以下信息:
n 字符串的大小
n 用於存儲該字符中的字符的內存的容量
n 字符串的值
n 它的分配子的一個拷貝,這個字段是可選的
n 對數的引用計數。
String的實現比咋看上去有更多的自由度;同樣明顯的是,不同的實現以不同的方式利用了這種設計上的靈活性。這些區別總結如下:
n String的值可能會被引用計數
n String對象大小的範圍可以是一個char*指針的大小的1-7倍
n 創建一個新的字符串值可能需要零次,一次或兩次動態分配內存
n String對象可能共享,也可能不共享其大小和容量信息。
n String可能支持,也可能不支持針對單個對象的分配子
n 不同的實現對字符內存的最小分配單位有不同的策略。
其實stl也有很多實現版本,每個版本的string實現都是不太一樣的。以後會再找一個string實現源碼具體分析。
第十六條瞭解如何把vector和string數據傳給舊的API
Vector和string的數據傳送到舊API方式:
n vector保證和數組具有同樣的佈局,可以直接把vector中的數據當做數組來對待。&V[0]即數組的首地址指針。反之亦然,可以將數組元素直接複製到vector的內存地址。
n String提供c_str()函數來返回一個指向字符串的值的指針,且可用於C。因爲string中的數據不一定是存儲在連續的內存中,而且不一定以空字符結尾。所以不能隨便修改指針指向內存的值,特意用顯式調用作爲提醒。
n 對於其他類型的stl容器,可以將數據先拷貝到vector,用vector作爲中介與舊API相互傳送數據