STL 概覽


概述

網上常見的說法是 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);
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM