std:vector的原始碼很容易找到,其實你看它**也不複雜,之所以看上去眼花繚亂的原因不是因為他複雜,而是為了相容和安全性搞了好多新功能和方法,再加上一些模板本身的技巧。這些都可以暫時忽略過去,重點看重點的相關的函式方法的實現。
向量的建構函式其實就是兩部分模板型別名稱和分配器,而分配器一般使用預設的分析器型別,這個回頭再分配器中再詳細分析。
template >
class vector )
explicit vector(const _alloc& _al) noexcept : _mypair(_one_then_variadic_args_t{}, _al)
......
public:
vector& operator=(vector&& _right) noexcept(noexcept(_move_assign(_right, _choose_pocma<_alty>{}))) );
}return *this;
}~vector() noexcept
......
void push_back(const _ty& _val)
void push_back(_ty&& _val)
template iterator emplace(const_iterator _where, _valty&&... _val) else
return _make_iterator(_whereptr);
}return _make_iterator(_emplace_reallocate(_whereptr, _std forward<_valty>(_val)...));
}iterator insert(const_iterator _where, const _ty& _val)
iterator insert(const_iterator _where, _ty&& _val)
......
void clear() noexcept
public:
void swap(vector& _right) noexcept /* strengthened */
}_nodiscard _ty* data() noexcept
_nodiscard const _ty* data() const noexcept
_nodiscard iterator begin() noexcept
_nodiscard const_iterator begin() const noexcept
_nodiscard iterator end() noexcept
_nodiscard const_iterator end() const noexcept
_nodiscard reverse_iterator rbegin() noexcept
_nodiscard const_reverse_iterator rbegin() const noexcept
_nodiscard reverse_iterator rend() noexcept
_nodiscard const_reverse_iterator rend() const noexcept
_nodiscard const_iterator cbegin() const noexcept
_nodiscard const_iterator cend() const noexcept
_nodiscard const_reverse_iterator crbegin() const noexcept
_nodiscard const_reverse_iterator crend() const noexcept
......
}
第二級 __default_alloc_template
其實就是維護乙個記憶體池,乙個鍊錶s_free_list可以把這些空閒的記憶體連線起來,寫過記憶體池或者接觸過的一說應該就明白,其大小為16。這16個鍊錶中每個鍊錶中的空閒空間的大小都是固定的8,16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, 128位元組。
那麼實際分配就好說了,大於128的使用第一種,否則使用當前記憶體池中的鍊錶遍歷,查詢可用空閒找到後直接使用,否則*8,呼叫refill再次分配。
釋放相對就簡單了,同樣分成兩部分,大於128位元組轉第乙個呼叫free,否則加入**空閒列表。
template pointer _emplace_reallocate(const pointer _whereptr, _valty&&... _val)
const size_type _newsize = _oldsize + 1;
const size_type _newcapacity = _calculate_growth(_newsize);
const pointer _newvec = _al.allocate(_newcapacity);
const pointer _constructed_last = _newvec + _whereoff + 1;
pointer _constructed_first = _constructed_last;
_try_begin
_alty_traits::construct(_al, _unfancy(_newvec + _whereoff), _std forward<_valty>(_val)...);
_constructed_first = _newvec + _whereoff;
if (_whereptr == _mylast) else
_catch_all
_destroy(_constructed_first, _constructed_last);
_al.deallocate(_newvec, _newcapacity);
_reraise;
_catch_end
_change_array(_newvec, _newsize, _newcapacity);
return _newvec + _whereoff;
}
在c++11中提供了shrink_to_fit()函式,可以減少相關的記憶體使用,不過需要注意的,一定要看使用後是否引起了迭代器的失效,如果已經失效一定要重新處理迭代器的引用,否則會引起崩潰。
#include #include #include void testadd()
vec.resize(100);
std::cout <
vec.shrink_to_fit();
std::cout <
}void testdel()
; std::vector::iterator it = vec.begin();
std::cout <
std::cout <
for (auto it = vec.begin(); it != vec.end(); it++)
}int main()
執行結果是:
vec size:1 vec capacity:1
vec value:1
vec value:0
vec value:2
vec value:3
vec size:100 vec capacity:100
vec size:100 vec capacity:100
first is:0end is:9
second is:1at three:3
vec content:1
vec content:2
vec content:3
vec content:4
vec content:5
vec content:6
vec content:7
vec content:8
vec content:9
vec content:
使用std::vector需要注意的有以下幾點:
1、空間的分配問題
不建議在小記憶體環境下申請使用較大的vector物件,容易引起記憶體的不足。前面提到過,如果使用預設的分配器,記憶體的處理會比實際需要的大好多,特別是做一些插入操作時,遇到臨界點會引起重新分配(大約是1.5到2倍)和拷貝,也很耗費時間。
2、自定義物件的操作符過載問題
如果使用自定義物件,因為迭代器的需要,一定在結構體或類中實現對操作符==,=及相關操作符的過載。
4、新增元素盡量使用emplace_back
原因是可以減少拷貝物件的次數。c++11提供的move語義也提供了更高效的方式。
其實寫這個stl,就很猶豫,畢竟前面有大神侯捷的stl原始碼剖析,而應用網上有官方的**,各種例程都很多並且相當清晰。但是為啥還是寫了下來呢,除了是讓中級c++篇更完善,另外乙個原因是想把更新的一些c++標準的東西揉合進來,不過限於個人的能力,可能會有不少問題,希望看到後,能及時提出來,共同進步。
跟我學C 中級篇 STL的容器Array
stl中的array陣列型別是在c tr1中才提出的,在之前只有vector這個類似於陣列的型別。但在實際應用中發現,vector和實際應用陣列還是有非常大的區別,包括迭代器訪問的控制,記憶體大小的控制等。用過vector的很容易發現它和實際使用中的陣列的諸多不同之處。換句話說,實際開發過程中,還是...
跟我學C 中級篇 STL的學習
c 的標準庫主要包含兩大類,首先是包含c的標準庫的,當然,為了適應c 對一些c庫進行了少許的修改和增加。最重要的當然是物件導向的c 庫 而c 庫又可以分成兩大類,即物件導向的c 庫和標準模板庫,也就是題目中的stl。另外在此基礎上,還要提醒同學們的是,除了上面的庫,在各個平台的開發廠商中,還會針對實...
跟我學c 中級篇 pimpl
private implementation,私有化實現。在c 中,由於語言本身的限制,沒有純粹的介面定義。這就導致了在介面的使用上很多c 的人員都是隨心而動。有用抽象類的純虛函式的,有直接用c型別的介面的。有乾脆提供介面類的 不一而足吧。根據實際情況,實事求是的選擇才是乙個好的標準。在c 中,大量...