Введение в STL — стандартную библиотеку шаблонов C++

Автор: | 7 июня, 2025

STL — это мощный набор обобщённых контейнеров, алгоритмов и итераторов, встроенный в стандарт C++. Она делает разработку более эффективной и безопасной.

Основные компоненты STL:

  1. Контейнеры: vector, list, deque, map, set, unordered_map, и др.
  2. Алгоритмы: sort, find, for_each, accumulate и др.
  3. Итераторы: позволяют универсальный доступ к элементам контейнеров.
  4. Функциональные объекты (функторы) и лямбда-функции.
  5. Адаптеры контейнеров и функций: stack, queue, priority_queue.

Пример: простой vector

#include <iostream>
#include <vector>

int main() {
    std::vector<int> numbers = {1, 2, 3, 4};
    numbers.push_back(5);

    for (int n : numbers) {
        std::cout << n << " ";
    }
    return 0;
}

std::vector — универсальный динамический массив

std::vector — это самый популярный контейнер STL. Он работает как массив с возможностью динамического изменения размера.

Примеры использования:

std::vector<std::string> names = {"Alice", "Bob", "Charlie"};
names.emplace_back("David");  // эффективнее, чем push_back
names.erase(names.begin() + 1); // удаление второго элемента

reserve(n) — резервирует память, снижает количество реаллокаций.

shrink_to_fit() — уменьшает выделенную память до фактического размера.

std::map и std::unordered_map — ассоциативные контейнеры

std::map<std::string, int> ages;
ages["Alice"] = 30;
ages["Bob"] = 25;

for (auto& [name, age] : ages) {
    std::cout << name << ": " << age << "\n";
}

std::unordered_map (на основе хеш-таблицы):

std::unordered_map<int, std::string> lookup = {{1, "один"}, {2, "два"}};
if (lookup.contains(2)) {
    std::cout << "есть ключ 2";
}

Когда использовать:

  • map — если важен порядок ключей.
  • unordered_map — если важна скорость доступа.

STL алгоритмы — мощные инструменты над контейнерами

#include <algorithm>
#include <numeric>  // accumulate

std::vector<int> v = {1, 2, 3, 4, 5};

std::sort(v.begin(), v.end(), std::greater<int>());
int sum = std::accumulate(v.begin(), v.end(), 0);
bool allPositive = std::all_of(v.begin(), v.end(), [](int n){ return n > 0; });

Полезные алгоритмы:

  • std::find, std::count, std::any_of, std::none_of
  • std::reverse, std::rotate, std::partition

Итераторы в STL и как они работают

Типы итераторов:

  • InputIterator
  • OutputIterator
  • ForwardIterator
  • BidirectionalIterator
  • RandomAccessIterator

Пример итерации:

std::vector<int> v = {10, 20, 30};
for (auto it = v.begin(); it != v.end(); ++it) {
    std::cout << *it << " ";
}

Специальные итераторы:

  • std::back_inserter(), std::istream_iterator, std::ostream_iterator

Адаптеры STL — stack, queue, priority_queue

#include <stack>
#include <queue>
#include <iostream>

std::stack<int> st;
st.push(10); st.push(20); st.pop();  // LIFO

std::queue<int> q;
q.push(1); q.push(2); q.pop();       // FIFO

std::priority_queue<int> pq;
pq.push(100); pq.push(50); pq.push(200);  // max-heap

std::set и std::multiset

std::set — это контейнер, хранящий уникальные элементы в отсортированном порядке.
std::multiset — позволяет хранить повторяющиеся элементы.

#include <set>

std::set<int> numbers = {3, 1, 4, 1, 5, 9};
numbers.insert(2);  // только уникальные значения

for (int n : numbers) {
    std::cout << n << " ";
}
// Вывод: 1 2 3 4 5 9
std::multiset<int> values = {10, 10, 20, 20, 30};
values.insert(10);  // можно вставить ещё одно 10

std::cout << values.count(10);  // 3

std::deque — двусторонняя очередь

std::deque (double-ended queue) позволяет быстро вставлять и удалять элементы как в начале, так и в конце.

#include <deque>

std::deque<int> d = {1, 2, 3};
d.push_front(0);  // [0, 1, 2, 3]
d.push_back(4);   // [0, 1, 2, 3, 4]

d.pop_back();     // [0, 1, 2, 3]

Преимущество над vector — эффективная вставка в начало.

Как писать собственные алгоритмы STL-стиля

template<typename Iterator>
void printRange(Iterator begin, Iterator end) {
    for (; begin != end; ++begin) {
        std::cout << *begin << " ";
    }
}


std::vector<int> v = {10, 20, 30};
printRange(v.begin(), v.end());

STL и многопоточность — что важно знать

STL-контейнеры не потокобезопасны по умолчанию, но их можно использовать при правильной синхронизации:

// Потокобезопасный доступ:

#include <mutex>
std::mutex mtx;
std::vector<int> data;

void addValue(int value) {
    std::lock_guard<std::mutex> lock(mtx);
    data.push_back(value);
}
// Очередь между потоками:

std::queue<int> q;
std::mutex m;
std::condition_variable cv;

void producer() {
    std::unique_lock<std::mutex> lock(m);
    q.push(42);
    cv.notify_one();
}

void consumer() {
    std::unique_lock<std::mutex> lock(m);
    cv.wait(lock, []{ return !q.empty(); });
    int val = q.front(); q.pop();
}
Раздел: STL Метки: