Современные компиляторы LLVM Clang и GNU GCC научились писать эффективный код даже из наивных исходников. Пример — знаменитый Q_rsqrt из Quake 3, который в конце 90-х обходил медленные FSQRT и FDIV. Сейчас у x86 есть инструкции rsqrtss и vrsqrtss, а у ARMv8 — frsqrte. Бенчмарки показали, что Q_rsqrt и наивный 1.0f / std::sqrt(x) сравнимы по скорости. Разница есть только на больших массивах, но она не оправдывает запутанный код. Лучше написать очевидную версию — компилятор сам превратит её в эффективную инструкцию.
То же с подсчётом битов. std::popcount из C++20 на x86 c флагом popcnt компилируется в одну инструкцию. Но даже старые трюки вроде цикла Кернигана и SWAR компилятор распознаёт и сворачивает в popcnt. Используйте <bit>.
Индексация через указатели на строки матрицы (row pointers) — ещё один пережиток. Бенчмарк с flat_matrix и nr_matrix показал, что разницы в производительности почти нет. Главное — непрерывное хранение данных и обход по строкам. Разбросанная по памяти матрица (scattered_matrix) проигрывает в разы.
Передача по const& везде — вредная привычка. Для функций-обёрток она убивает семантику перемещения. Бенчмарк: с perfect forwarding строка вставляется в std::vector в два-три раза быстрее, чем с const&. Используйте T const& для наблюдения, T по значению для копирования, forwarding references для обёрток.
Стандартная библиотека теперь не уступает ручным циклам. Бенчмарк: сырой цикл, std::accumulate и std::ranges::fold_left с пайплайном преобразований работают одинаково. Разница в пределах шума.
Исключения — быстры, только пока ничего не бросается. Как только частота ошибок достигает 5%, производительность падает на порядок. Для ожидаемых сбоев (парсинг, поиск) используйте std::expected. Для безвыходных ситуаций (out-of-memory) — исключения.
Виртуальные вызовы в горячих циклах с закрытым набором типов лучше заменить на std::variant. Бенчмарк: std::vector<std::variant<circle_v, square_v>> обходит std::vector<std::unique_ptr<shape>> в 30 раз на миллионе элементов — из-за линейного хранения в кэше, а не из-за механизма диспетчеризации.
Вывод: пишите код прямо. Современный C++ с std::expected, std::variant, <bit>, std::bit_cast, ranges и стандартными алгоритмами даёт и производительность, и читаемость. Первая оптимизация — убрать «хитрый» код. Доверяйте компилятору.