C++MiddleExperience

Для каких задач C++ является сильным выбором, а где лучше честно выбрать другой язык?

C++ оправдан для систем с жёсткими требованиями к латентности и памяти (HFT, game engines, embedded, компиляторы); для CRUD-сервисов, скриптов и команд без C++-экспертизы лучше Go, Python или Rust.

Когда C++ — правильный выбор

C++ остаётся незаменимым в задачах, где требуется максимальный контроль над памятью и предсказуемая латентность без GC-пауз:

  • Системное программирование — ядра ОС, драйверы, гипервизоры (QEMU, KVM). Нулевые накладные расходы на абстракции.
  • Game engines — Unreal Engine, id Tech: физика, рендер, аудио требуют детерминированного времени кадра. GC-паузы в 50+ мс неприемлемы.
  • HFT и low-latency trading — latency p99 < 1 мкс. Используют std::atomic, lock-free очереди, memory-mapped файлы.
  • Embedded без ОС — микроконтроллеры ARM Cortex-M: -ffreestanding, без стандартной библиотеки, ручное управление стеком.
  • Компиляторы и runtime-ы — LLVM, V8, CPython написаны на C++. Тонкий контроль над layout структур.
  • Мультимедиа и CV — OpenCV, FFmpeg: SIMD-оптимизации через intrinsics (_mm256_add_ps), векторизация компилятором.

Пример: lock-free очередь для HFT

#include <atomic>
#include <array>

template<typename T, std::size_t N>
class SPSCQueue {
    std::array<T, N> buf_;
    alignas(64) std::atomic<size_t> head_{0};
    alignas(64) std::atomic<size_t> tail_{0};
public:
    bool push(const T& val) {
        size_t t = tail_.load(std::memory_order_relaxed);
        size_t next = (t + 1) % N;
        if (next == head_.load(std::memory_order_acquire)) return false;
        buf_[t] = val;
        tail_.store(next, std::memory_order_release);
        return true;
    }
    bool pop(T& val) {
        size_t h = head_.load(std::memory_order_relaxed);
        if (h == tail_.load(std::memory_order_acquire)) return false;
        val = buf_[h];
        head_.store((h + 1) % N, std::memory_order_release);
        return true;
    }
};

Здесь alignas(64) предотвращает false sharing между ядрами, memory_order_acquire/release даёт корректную синхронизацию без полного барьера.

Когда C++ — плохой выбор

  • CRUD-сервисы и API — Go, Python, Kotlin дают в 3–5 раз быстрее time-to-market. Разница в производительности нивелируется сетью и БД.
  • Скрипты и автоматизация — Python/Bash на порядок проще. Компиляция и отсутствие REPL замедляют итерации.
  • Команда без C++-экспертизы — UB (undefined behavior), висячие ссылки, use-after-free приводят к трудно диагностируемым багам в production.
  • Быстрые прототипы ML-моделей — Python + PyTorch достаточно. C++ нужен только для inference-оптимизации (TensorRT, ONNX Runtime).
  • Мобильные приложения — Swift/Kotlin дают лучший DX, безопасность памяти, интеграцию с платформой.

Сравнение с ближайшими альтернативами

  • Rust — сопоставимая производительность, borrow checker исключает data races и use-after-free на этапе компиляции. Найм сложнее, экосистема меньше, но растёт.
  • C — проще, предсказуемее, но нет RAII, шаблонов, умных указателей. Приходится вручную управлять ресурсами.
  • Go — GC с паузами <1 мс (Go 1.18+), goroutines. Хорош для сетевых сервисов, плох для real-time задач с жёсткими latency-требованиями.

Подводные камни

  • Недооценка стоимости code review и онбординга: junior-разработчик на C++ без опыта создаёт UB-баги, которые воспроизводятся только в release-сборке.
  • Игнорирование AddressSanitizer (-fsanitize=address) и UBSanitizer в CI — утечки памяти уходят в production.
  • Смешивание C-стиля (malloc/free, сырые указатели) с C++11+ RAII — ломает exception safety.
  • Отсутствие единого пакетного менеджера: Conan vs vcpkg vs submodules — нет очевидного стандарта, в отличие от npm или pip.
  • Переоценка «нулевой стоимости абстракций»: виртуальные функции, std::function, исключения добавляют реальные накладные расходы на критических путях.
  • Забывают про ABI-совместимость: обновление компилятора или флагов может сломать бинарную совместимость между shared libraries.
  • Время компиляции больших проектов (Chromium — часы): без precompiled headers, unity builds или clangd LSP разработка тормозит.

What hurts your answer

  • Выбирать C++ по популярности, а не по требованиям проекта
  • Игнорировать опыт команды, эксплуатацию и стоимость поддержки
  • Не называть ситуации, где C++ будет плохим выбором

What they're listening for

  • Называет критерии выбора C++
  • Учитывает команду, эксплуатацию, стоимость и риски
  • Может назвать сценарии, где выбрал бы альтернативу

Related topics