Заметки про код-стайл в C++

Мысли о нейминге приватных переменных в C++ и неочевидные моменты из стандарта, о которых легко забыть в реальном коде

Типизированный язык программирования

Мысли о нейминге приватных переменных в C++ и неочевидные моменты из стандарта, о которых легко забыть в реальном коде

Если бы Кардинал Ришелье был программистом, он бы сказал: «Дайте мне шесть строк кода, написанных рукой самого профессионального C-программиста в мире, и я найду в них лазейку для вызова неопределённого поведения.
Никто не может написать безошибочный код на С или C++. И я говоря об этом как человек, который пишет на этих языках почти каждый день около 30 лет. Я слушаю подкасты по C++. Я смотрю выступления про C++ на конференциях. Мне нравится читать и писать на этом языке.
C++ послужил нам сполна, но на дворе 2026 год, и современная рабочая среда явно отличается от среды 1985 (C++) или 1972 (С).
И я далеко не первый, кто об этом заговорил. Помню ещё с десять лет назад читал статью какого-то известного человека, в которой он утверждал, что использование C++ вполне обоснованно можно подвести под нарушение закона Сарбейнза-Оксли (SOX). И хотя с остальной его критикой я не был согласен (как и с тем, что он путал «its» и «it’s»), конкретно с этим пунктом я никогда не спорил.
Мало того, со временем я всё больше убеждался в его истинности. На деле в С для возникновения неопределённого поведения (undefined behaviour, UB) есть гораздо больше возможных причин, чем вы могли предполагать.
Все знают, что двойное освобождение памяти, её использование после освобождения, выход за границы объекта (например, массива) и чтение неинициализированной памяти — это UB. Как ни крути, но в контексте работы с памятью C и C++ безопасными не назовёшь. Тем не менее даже эти ошибки продолжают совершаться повсеместно раз за разом.
В этой статье мы на практическом примере разберём создание консольной симулятора файтинга на C++ с двумя персонажами на арене. Вы увидите, как работают основные принципы ООП: инкапсуляция, наследование и полиморфизм. Мы реализуем базовый класс Character и трёх наследников — Warrior, Orc и Magician — каждый со своими уникальными атаками, дальностью обнаружения врага и поведением (преследование / побег). Также покажем простейшую анимацию выстрелов, отрисовку карты 14×14 и игровой цикл с пошаговой логикой боя. Статья будет полезна новичкам, которые уже знакомы с синтаксисом C++ и хотят увидеть, как теория превращается в работающую игру.

Сотни строк кода, страницы документации, корпоративные чаты — и всё это каждый день. Когнитивная нагрузка не снижается. Внутри — система инструментов, которая помогает мне не тонуть: конфиги clang и специфичные настройки VSCode, приложения визуализации и др. С объяснением зачем каждый из них.

Segmentation fault - одна из тех ошибок, с которой сталкивался каждый, но мало кто разбирался что за ней стоит. В этой статье копаем глубже обычного: смотрим как ядро Linux понимает что произошло, какие типы ошибки бывают - с реальными примерами и исходниками ядра Linux.

Если нужно спрятать дерево, прячьте его в лесу. Лес интернета состоит из TLS-соединений (>70% трафика, если верить статистике): вкладок браузера, WebSocket-потоков, долгоживущих HTTPS-запросов, клиентов игр, мобильных приложений, телеметрии, видеоплееров, чатов и тысяч спокойных TCP/443-соединений, которые выглядят настолько обычно, что именно это и делает их интересной средой для, кхм, исследования.
Очевидно, единственная и конечная цель существования интернета — быть распределённым хранилищем порно, так почему бы не использовать его по прямому назначению и не хранить смешные картинки прямо в трафике?

У меня есть книга, которая называется Game++ и несколько статей, где я разбирал какие паттерны применяются в играх и движках. В книге почти сто страниц отведено про эти самые паттерны и подробно рассказано какие они бывают, как выглядят в C++, где у них подводные камни и как их применять. Т.е. ровно те мелочи реализации, которые обычно интересно перечитать, когда вы в очередной раз решаете делать фабрику отдельным классом или попробовать обойтись std::function. Когда я её писал, мне казалось, что это будет очень полезный практический текст, и он таким и получился, и человек с опытом довольно быстро находит там нужное.
Но если читать книгу целиком, а не эти отдельные главы, то хорошо видно, как я по неопытности и уверенности молодого автора в собственной правоте взял с места в карьер и сразу начал рассказывать про реализации, как будто читатель уже всё для себя решил и его интересует только синтаксис, предположив, что мы все тут делаем условный AAA-движок, в котором сериализация неизбежна, а скрипты обязательны. В результате получился классический случай, когда книжка отвечает на вопрос «как», но обходит вопрос «а собственно зачем», а без ответа на него все ответы про «как» оказываются либо случайно-полезными, либо системно-вредными, потому что человек берёт оттуда подход, переносит его в проект или прикручивает к своей мини-игре и потом жалуется, что у него теперь полторы тысячи строк инфраструктуры на ту же мини-игру, а работает она ровно так же, как раньше, только медленнее.
Если вам вдруг надоест читать эти 106 минут, там в конце есть TL;DR секция, где собрано краткое описание.

Добрый день, коллеги!
Разрабатывали очередной аутсорсный заказ и в процессе разработки поняли с командой, что это может быть довольно интересным универсальным продуктом. В статье (без подробностей) расскажу, что изначально делали и что получили в итоге.
Совместно с заказчиком продумывали идею автоматизации производства. Они занимаются разработкой и изготовлением отечественных электронных компонентов, но процесс измерения основных параметров делался оператором вручную, с использованием 2-ух отдельных средств измерений, поочередно и по одному фильтру за раз.
Мы предложили автоматизировать этот процесс, разработать систему измерения, к которой можно будет подключить оба измерителя, до 10 тестовых образцов с механическим креплением на контактирующих устройствах, персональный компьютер с программным обеспечением, которое будет управлять всей системой, автоматически генерировать протокол измерений, собирать статистику и максимально упростит задачу оператора.
Разрабатывая решение под конкретную задачу конкретного заказчика, мы получили довольно универсальный мультиплексор, который могут использовать любые лаборатории для автоматизации своих измерительных процессов.

По следам моей публикации "Программируем SFP-модули на программаторе CH341A". Программа SFP-master была портирована c Qt5 на Qt6. Модуль "общения" с интерфейсом I2C был полностью переписан, стал значительно проще, короче и надежней. Сейчас доступна версия v1.1.1. Русскоязычное описание программы я выложил здесь. Поэтому повторять его здесь смысла нет.

Raptor Engine: Как 30 000 строк кода на TypeScript вдохнули жизнь в компилятор AsmX
Можно ли объединить абсолютный контроль низкоуровневого ассемблера x86-64 с изяществом ООП, шаблонов и безопасных абстракций в духе C++? Разбираем масштабное обновление отечественного компилятора AsmX. Под капотом — честные 30 тысяч строк хардкорной архитектуры: от прямого доступа к аппаратной SIB-адресации CPU и хитрых махинаций с регистрами при вызове знаковых movsx/imul/idiv, до разбора анатомии новой стандартной библиотеки (std::optional и std::pair), работающей по принципу Zero-Cost Abstractions. Узнайте, как мономорфизация AST-деревьев и System V ABI позволяют выжимать максимум из кремния без единого байта накладных расходов.

Получится ли сделать полноценную 3D-игру на Qt Quick3D?
Именно такой вопрос у меня возник, когда я начал изучать Quick3D. Казалось бы, рендер и партиклы есть, базовая физика в лице Quick3D Physics тоже присутствует. Пример CharacterController из Qt указывал на то, что проблем быть не должно.
Но хотелось проверить это самому на чём-то реальном.
Поскольку моделлер и художник из меня никакой, да и в геймдеве опыта у меня меньше нуля, я решил переписать Quake — любимую игру своего детства. В ней я провёл сотни (тысячи?) часов, играя в мультиплеер на бесплатных серверах МТУ-Информ через модем US Robotics 33600.
В итоге получился проект Kwayk — попытка переписать Quake на Quick3D.

Если у вас кроссплатформенный проект на C или C++, то, как правило, вы не завязываетесь на одну систему сборки, а используете генератор сценариев для сборочных систем. Самый распространённый из них, CMake, недавно получил официальную интеграцию со статическим анализатором PVS-Studio для этих языков.
Самодельный генератор псевдослучайных чисел (ГПСЧ) стал побочным продуктом работы над любительским шифром, а шифры для меня всего лишь хобби и поле для творчества и экспериментов. Поскольку в своём шифре я делал упор на заранее непредсказуемые динамические связи, которые зависят от промежуточных состояний шифра, сама собой напросилась идея о применении этой непредсказуемости для генерации псевдослучайных чисел. Нужно было лишь оценить степень случайности полученного генератора. Как выполнялась оценка, что показали тесты NIST и сравнение с известными «эталонами» — далее в статье.

Всем добра! Речь пойдет о ресивере Yamaha RX-V575 и телевизоре Samsung UE50F6800AB. Оба устройства не первой свежести, более того, телевизор имеет устаревший и не развиваемый более интерфейс. Однако, полученные результаты могут оказаться полезными для владельцев множества других устройств Yamaha и Samsung. Не все ведь меняют технику ежегодно :)
Статья является логическим продолжением материала об универсальном голосовом шлюзе в том смысле, что показывает куда может двигаться мысль в части улучшения комфорта. Т.е., как и раньше, идея состоит не в том, чтобы разбирать детали, а в том чтобы показать ход мысли. Для деталей есть репозиторий с комментариями.
Сразу оговорюсь, что не стоит дальше читать, если вы:

Одна из самых неприятных особенностей production-проблем заключается в том, что они почти никогда не происходят тогда, когда разработчик готов их исследовать.
Во время разработки всё работает. На тестовом стенде тоже всё выглядит нормально. Логи кажутся вполне достаточными, а диагностическая информация — продуманной и аккуратно организованной. Но затем в production внезапно появляется странная проблема: соединение иногда сбрасывается без видимой причины, один запрос из нескольких тысяч начинает вести себя иначе, сервер под высокой нагрузкой неожиданно входит в reconnect loop или где-то глубоко внутри системы начинает происходить что-то, что невозможно воспроизвести локально.
И почти всегда в этот момент выясняется одна и та же неприятная вещь: логов, которые уже есть в системе, недостаточно.
Именно здесь традиционное логирование начинает постепенно ломаться.
Большинство систем логирования до сих пор построены вокруг довольно простой идеи: заранее решить, какие сообщения должны писаться постоянно. Разработчик добавляет INFO, WARNING, DEBUG, иногда каналы или категории, после чего приложение отправляется в production с надеждой, что этих логов когда-нибудь хватит для диагностики.
Иногда действительно хватает.
Но реальные production-системы имеют неприятную привычку ломаться не там и не так, как ожидалось. Более того, проблемы часто возникают именно в тех участках кода, которые казались совершенно неинтересными во время разработки.
Первой реакцией обычно становится мысль: “давайте включим DEBUG logging”. На небольших проектах это ещё может работать вполне нормально. Однако в больших системах DEBUG-логи очень быстро превращаются в проблему сами по себе. Они начинают занимать гигабайты, полезная информация тонет в шуме, растёт нагрузка на диск, а иногда и само логирование начинает заметно влиять на производительность и тайминги приложения.

Вот, например, Milvius(DiskANN) рассчитан на вектора размерности до 32 768, но это приближенный поиск. Но как насчёт поиска точного?
В данной статье рассматривается работоспособность 1024 мерного индекса, хранилищем которого служит обычное B‑дерево (насколько вообще может быть обычным такое дерево). Используемый диск — вполне себе «железный» старый добрый WD Purple, оперативная память сознательно ограничена 8 Гб. Можно ли что‑то из этого выжать на рядовом десктопе за приемлемое время?

В прошлой статье я разобрал, как работает квалифицированный поиск и как using namespace участвует в нём только в качестве запасного варианта, когда собственных объявлений в указанной области нет. Компилятор сначала смотрит, что объявлено непосредственно в текущем контексте, и только при неудаче переходит к именам, подмешанным через директиву using. Казалось бы, схема прозрачная и предсказуемая: есть область поиска, есть приоритет явных объявлений, есть «правило N-объявлений» как страховка.
Но как только мы переходим от переменных и функций к более общим механизмам в коде, эта прозрачность сразу начинает ломаться, причём в самом обыденном коде, который пишет каждый разработчик с первых дней обучения. По правилам языка мы можем разместить директиву using namespace где угодно, но если в области, указанной в квалификаторе, что-то объявлено явно, квалифицированный поиск найдёт именно это объявление, и лишь если явно объявленного имени нет, компилятор начинает учитывать имена, ставшие видимыми через using namespace, и так далее по цепочке.
Но тут есть скользкое место, о котором умалчивает большинство учебников и курсов, обходя вниманием работу с операторами. Например оператор сдвига влево <<, может быть определён в любом пространстве имён.

Друзья, знаю, что интернет переполнен воспеванием AI, что вызывает у многих людей (особенно специалистов) фрустрацию, особенно когда речь заходит о написании кода на C/C++. Я не AI-проповедник – просто активный и ответственный программист, который пользуется AI-инструментами. Недавно я предложил AI (если быть точнее, opencode + GLM-5.1) придумать алгоритм для одной из задач, над которой я работаю, и он справился очень хорошо. Это не прорывной алгоритм, на котором я разбогатею, но он интересный: составленный из известных компонентов, но всё же новый. В статье расскажу:
Как решать задачу “дана битовая строка, нужно найти все позиции в ней, что количество единиц минус количество нулей до этой позиции равно заданному числу”
Что мне придумал AI для этой задачи
Что я использую для того, чтобы AI писал что-то адекватное на C++
Если вам интересны алгоритмы и структуры данных, то описанная задача используется в контексте RMQ/LCA.

Привет, Хабр!
Полгода назад я рассказывал, как прикрутил мозги к своему гидравлическому прессу и что из этого получилось. С тех пор много воды (и масла!) утекло, сделал много нового и хочу этим поделиться.
На тот момент было несколько моделей контроллеров, вот флагманская модель

Приветствую Вас, дорогой читатель! В этот раз представляю Вашему вниманию цикл статей, который будет посвящён одной из важнейших тем в программировании на Vulkan API - использование асинхронности и параллелизма для написания производительных движков.
Данный цикл не является туториалом, а лишь моей попыткой исследования основных аспектов асинхронного программирования на Vulkan API. Целью данного исследования - разработать архитектуру, упрощающую управление многопоточным выполнением, в основу которой будет положено использование корутин c++20.
Это статья будет посвящена вводной части. Мы разработаем терминологию, погрузимся в детальное исследование аспектов синхронизации, а также введём требования для нашей архитектуры.