概述
网上常见的说法是 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);
}