Руководство и документация по языку программирования C++

Фундаментальный разбор языка C++ и стандарта ISO: трансляция кода, системное управление памятью, RAII, шаблоны (Templates), Move-семантика, STL и стандарты C++17/C++20/C++23.

Важное примечание по стандартам и компиляторам: Язык C++ развивается по трехлетнему циклу стандартизации (C++11, C++14, C++17, C++20, C++23). Поведение кода может различаться в зависимости от компилятора (GCC, Clang, MSVC) и выбранного уровня оптимизации. Всегда используйте флаги предупреждений компилятора (например, -Wall -Wextra -Werror или /W4) и ориентируйтесь на современный C++ (Modern C++), избегая сырых указателей и опасных си-стилей.

1. Экосистема C++, препроцессинг и линковка (Toolchain)

Язык программирования C++ — это высокопроизводительный компилируемый язык общего назначения с прямой поддержкой низкоуровневых операций над памятью и процессором. Процесс превращения исходного текста программ (файлы .cpp и .hpp) в исполняемый бинарный файл включает три ключевых этапа:

2. Управление памятью: Стек, Куча, RAII и Умные указатели

В C++ отсутствует автоматический сборщик мусора (Garbage Collector). Разработчик напрямую контролирует жизненный цикл каждого байта памяти. Память программы логически разделена на стек (Stack) и кучу (Heap / Free Store):

Для гарантированного предотвращения утечек ресурсов в современном C++ используется парадигма RAII (Resource Acquisition Is Initialization) и умные указатели (Smart Pointers) из заголовка <memory>:

#include <iostream>
#include <memory>
#include <string>

class UserProfile {
private:
    int id;
    std::string username;

public:
    UserProfile(int id, std::string name) 
        : id(id), username(std::move(name)) {}

    void displayInfo() const {
        std::cout << "ID: " << id << " | User: " << username << "\n";
    }
};

void executeUserSession() {
    // RAII: Уникальное владение объектом в куче. Автоматически удалится при выходе из функции
    auto user = std::make_unique<UserProfile>(101, "Alex");
    user->displayInfo();
}
Разбор умных указателей: std::unique_ptr реализует монопольное владение ресурсом (его нельзя скопировать, только переместить). std::shared_ptr использует счетчик ссылок для разделяемого владения, а std::weak_ptr предотвращает циклические ссылки.

3. ООП, Правило пяти и Семантика перемещения (Move Semantics)

ООП в C++ поддерживает множественное наследование, виртуальные функции и полиморфизм через таблицы виртуальных методов (vtable). Начиная со стандарта C++11, фундаментальным улучшением стала семантика перемещения (Move Semantics), избавляющая от дорогостоящего глубокого копирования данных.

Если класс вручную управляет ресурсами (указателями, файловыми дескрипторами), он должен соблюдать Правило пяти (Rule of Five) — явно определить или запретить 5 специальных функций-членов:

#include <utility>

class BufferManager {
private:
    size_t size;
    int* data;

public:
    // 1. Конструктор
    explicit BufferManager(size_t s) : size(s), data(new int[s]{}) {}

    // 2. Деструктор
    ~BufferManager() { delete[] data; }

    // 3. Конструктор копирования
    BufferManager(const BufferManager& other) : size(other.size), data(new int[other.size]) {
        for (size_t i = 0; i < size; ++i) data[i] = other.data[i];
    }

    // 4. Перемещающий конструктор (Rvalue reference &&)
    BufferManager(BufferManager&& other) noexcept 
        : size(other.size), data(other.data) {
        other.size = 0;
        other.data = nullptr;
    }

    // 5. Операторы присваивания (копирующий и перемещающий)
    BufferManager& operator=(BufferManager&& other) noexcept {
        if (this != &other) {
            delete[] data;
            size = other.size;
            data = other.data;
            other.size = 0;
            other.data = nullptr;
        }
        return *this;
    }
};

4. Шаблонное программирование (Templates) и Концепты (Concepts)

Шаблоны (Templates) обеспечивают метапрограммирование на этапе компиляции. В отличие от дженериков в Java/C#, шаблоны C++ генерируют отдельный оптимизированный код под каждый тип аргумента (Monomorphization), что исключает накладные расходы во время выполнения (Zero-cost Abstractions).

Начиная с C++20, ограничения шаблонов проверяются с помощью Концептов (Concepts), что кардинально улучшает понятность ошибок компилятора:

#include <concepts>
#include <iostream>

// Определение концепта: тип должен поддерживать сложение и сравнение
template <typename T>
concept Numeric = std::is_arithmetic_v<T>;

// Определение концепта: тип должен поддерживать сложение и сравнение
template <typename T>
concept Numeric = std::is_arithmetic_v<T>;

// Функция, ограниченная концептом Numeric
template <Numeric T>
T calculateSum(T a, T b) {
    return a + b;
}

int main() {
    std::cout << calculateSum(10, 20) << "\n";     // Успешно: int
    // calculateSum("A", "B");                     // Ошибка компиляции: string не удовлетворяет Numeric
}

5. Стандартная библиотека шаблонов (STL) и алгоритмы

STL (Standard Template Library) предоставляет мощный набор готовых контейнеров, итераторов и алгоритмов. Выбор верного контейнера определяет временную сложность операций (Big O):

Контейнер STL Структура данных Временная сложность (Доступ / Вставка)
std::vector<T> Динамический непрерывный массив Доступ: O(1) | Вставка в конец: O(1) amortized
std::unordered_map<K, V> Хеш-таблица (Hash Table) Поиск/Вставка: O(1) average, O(N) worst case
std::map<K, V> Красно-черное дерево (Red-Black Tree) Поиск/Вставка: O(log N) — всегда отсортирован
std::span<T> (C++20) Невладеющее представление массива Zero-allocation обертка над непрерывной памятью

Использование диапазонных алгоритмов (Ranges library из C++20):

#include <vector>
#include <algorithm>
#include <ranges>
#include <iostream>

void processScores() {
    std::vector<int> scores = {15, 42, 8, 23, 90, 4};

    // Декларативная фильтрация и трансформация с помощью C++20 Ranges
    auto results = scores 
        | std::views::filter([](int n) { return n >= 10; })
        | std::views::transform([](int n) { return n * 2; });

    for (int val : results) {
        std::cout << val << " "; // Выведет: 30 84 46 180
    }
}

6. Многопоточность, асинхронность и атомарные операции

Язык C++ поддерживает нативную модель многопоточности начиная со стандарта C++11 через библиотеку <thread>. Для синхронизации потоков и защиты критических секций от состояния гонки (Data Race) используются мьютексы (std::mutex, std::scoped_lock) и атомарные типы (std::atomic<T>).

#include <thread>
#include <mutex>
#include <future>
#include <iostream>

std::mutex g_num_mutex;
int g_counter = 0;

void safeIncrement() {
    // RAII-защита мьютекса: захватывает при создании, освобождает при выходе из скоупа
    std::lock_guard<std::mutex> lock(g_num_mutex);
    ++g_counter;
}

int asyncCompute(int input) {
    return input * 42;
}

void runConcurrencyExample() {
    // Запуск асинхронной задачи с получением std::future
    std::future<int> futureResult = std::async(std::launch::async, asyncCompute, 10);

    // Выполнение работы в главном потоке...
    int res = futureResult.get(); // Ожидание и получение результата (420)
    std::cout << "Асинхронный результат: " << res << "\n";
}