概述
網上常見的說法是 STL 包含六大組件。
- 容器 container
- 算法 algorthm
- 迭代器 iterator
- 仿函數 function object
- 適配器 adaptor
- 空間配置器 allocator
抄襲鏈接:https://www.jianshu.com/p/497843e403b4
容器
下面列舉幾種常見的容器:
- vector 容器
- deque 雙端數組
- stack 棧模型
- queue 隊列模型
- list 鏈表模型
- priotriy_queue 優先級隊列
- set 與 multiset 容器
- map 與 multimap 容器
- string
算法
STL 中的算法可以分為以下幾類。(網上抄的,鏈接找不到了)
- 只讀算法:查找和計數
- 可變序列算法:復制、變換、替換、填充、移除和隨機生成
- 排序算法
- 比較算法
- 堆算法
- 各個容器特有算法
迭代器
迭代器提供了用於遍歷元素的 “指針”,容器和算法之間可以通過迭代器聯系起來。迭代器有“前向”和“后向”的區別,有“常量”和“非常量”的區別。對於迭代器,++i 通常是要比 i++ 要快的。比如 vector 中實現為這個樣子:
_Vector_iterator& operator++() noexcept {
_Mybase::operator++();
return *this;
}
_Vector_iterator operator++(int) noexcept {
_Vector_iterator _Tmp = *this;
_Mybase::operator++();
return _Tmp;
}
仿函數
在沒有 lambda std::function, 之前通過重載 operator() 來實現類似函數的行為。比如下面的 plus,實際上是一個結構體,重載了圓括號操作符,它的對象就可以像函數一樣被調用了。
// 庫函數中 plus 的實現
// STRUCT TEMPLATE plus
template <class _Ty = void>
struct plus {
_CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef _Ty _FIRST_ARGUMENT_TYPE_NAME;
_CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef _Ty _SECOND_ARGUMENT_TYPE_NAME;
_CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef _Ty _RESULT_TYPE_NAME;
_NODISCARD constexpr _Ty operator()(const _Ty& _Left, const _Ty& _Right) const {
return _Left + _Right;
}
};
// 自己實現一個
template <typename T, typename Container>
struct Sum
{
Sum() {
cout << "Sum construct" << endl;
}
T operator()(Container container) {
T acc = T(0);
for (auto x : container) {
acc += x;
}
return acc;
}
};
int main() {
vector<int> arr = { 1, 2, 3, 5 };
auto x = accumulate(arr.cbegin(), arr.cend(), 0, plus<int>());
Sum<decltype(arr)::value_type, decltype(arr)> sum_functor;
Sum<decltype(arr)::value_type, decltype(arr)> sum_functor1{};
Sum<decltype(arr)::value_type, decltype(arr)> sum_functor2 = Sum<decltype(arr)::value_type, decltype(arr)>();
Sum<decltype(arr)::value_type, decltype(arr)> sum_functor3(); // 這個是啥語法啊
auto y = sum_functor(arr);
cout << x << " " << y << endl;
return 0;
}
適配器
一種設計模型。這就好像香港的充電器需要使用一個適配器才可以插到插座上。
STL 當中的 stack, queue, priority_queue 三種容器就是適配器。對於適配器,它可以接收一個容器,然后提供 stack 需要的接口,比如 push, pop 等方法。內部實現就是調用容器的方法去 push, pop。
template <class _Ty, class _Container = deque<_Ty>>
class stack;
template <class _Ty, class _Container>
class stack {
public:
using value_type = typename _Container::value_type;
using reference = typename _Container::reference;
using const_reference = typename _Container::const_reference;
using size_type = typename _Container::size_type;
using container_type = _Container;
static_assert(is_same_v<_Ty, value_type>, "container adaptors require consistent types");
stack() = default;
explicit stack(const _Container& _Cont) : c(_Cont) {}
// ...
}
分配器
負責內存管理,分配內存。allocator 提供了幾個方法進行分配回收內存和對象構造析構:allocate, deallocate, construct, destory, address, max_size。如果調用 deallocate 沒有調用 destory,那么不會調用類的析構函數。
參考:https://vimsky.com/zh-tw/examples/usage/stdallocator-in-cpp-with-examples.html
class Apple {
public:
Apple() {
cout << "apple construct" << endl;
}
~Apple() {
cout << "apple desstruct" << endl;
}
};
int main() {
allocator<Apple> apple_alloc;
Apple* apples = apple_alloc.allocate(10);
apple_alloc.construct(apples);
apple_alloc.construct(apples + 1);
apple_alloc.destroy(apples);
apple_alloc.destroy(apples + 1);
return 0;
}
vector 中的 reverse 方法就是調用了 allocator 去分配內存。
void reserve(_CRT_GUARDOVERFLOW const size_type _Newcapacity) {
// increase capacity to _Newcapacity (without geometric growth), provide strong guarantee
if (_Newcapacity > capacity()) { // something to do (reserve() never shrinks)
if (_Newcapacity > max_size()) {
_Xlength();
}
_Reallocate_exactly(_Newcapacity);
}
}
void _Reallocate_exactly(const size_type _Newcapacity) {
// set capacity to _Newcapacity (without geometric growth), provide strong guarantee
auto& _My_data = _Mypair._Myval2;
pointer& _Myfirst = _My_data._Myfirst;
pointer& _Mylast = _My_data._Mylast;
const auto _Size = static_cast<size_type>(_Mylast - _Myfirst);
const pointer _Newvec = _Getal().allocate(_Newcapacity);
_TRY_BEGIN
_Umove_if_noexcept(_Myfirst, _Mylast, _Newvec);
_CATCH_ALL
_Getal().deallocate(_Newvec, _Newcapacity);
_RERAISE;
_CATCH_END
_Change_array(_Newvec, _Size, _Newcapacity);
}