Читая разные C++-кодовые базы, можно заметить хаос в code style'ах. Qt использует к camelCase, стандартная библиотека и Boost используют snake_case, где-то любят PascalCase. Дополнительно хочу отметить нейминг приватных членов класса. Есть несколько часто встречающихся стилей:
_member // Подозрительно!
m_member
member_Но у C++ в этом плане есть пара подводных мин. Некоторые имена зарезервированы стандартом для реализации: компилятора, стандартной библиотеки, рантайма и прочих приколов.
Что говорит стандарт
В разделе [lex.name] (пункты 4.1 — 4.2) черновика стандарта C++ указано, что часть идентификаторов зарезервирована для реализации и не должна использоваться пользовательским кодом. В частности, идентификаторы с двойным подчёркиванием __ где угодно, а также идентификаторы, начинающиеся с подчёркивания и заглавной буквы, зарезервированы для реализации для любого использования. Отдельно сказано, что идентификаторы, начинающиеся с подчёркивания, зарезервированы для реализации как имена в глобальном пространстве имён. Диагностика при этом не обязательна.
Если коротко:
class Widget {
private:
int _size; // обычно допустимо: член класса, _ + lowercase
int _Toggle; // плохо: _ + uppercase, зарезервировано
int __cache; // плохо: содержит __, зарезервировано
int size_; // обычно допустимо
int size__x; // плохо: содержит __, зарезервировано
};
int _global; // плохо: имя в глобальном namespace, начинается с _Значит ли это, что название переменной _size в классе запрещено?
Нет. И это как раз место, где легко ошибиться.
class Widget {
private:
int _size;
};Такое имя обычно не нарушает правило стандарта, потому что это не глобальное имя, но проблема в другом: стиль с leading underscore легко превращается в минное поле.
Сегодня мы назвали переменную:
int _size;Завтра кто-то добавил акроним:
int _URL;И всё: _ + uppercase — зарезервировано для реализации, ровно также как и данное имя:
int __cache;
// Или такое:
int cache__line;То есть имя переменной _member — не всегда нарушение. Но это стиль, который стоит слишком близко к границе, за которой начинается уже не вопрос вкуса, а нарушение правил языка.
Почему это может отстрелить вам ногу?
Потому что реализация имеет право использовать зарезервированные идентификаторы для своих нужд. Например, внутри стандартной библиотеки, системных заголовков, ABI-слоя, внутренних макросов и прочей инфраструктуры.
Raymond Chen в статье Microsoft DevBlogs отдельно показывает те же категории: name, Name, name в глобальной области и namepart в C++ попадают в опасную зону; он также отмечает, что популярная конвенция с подчёркиванием перед приватными членами легко ломается на имени вида _Toggle.
И самое неприятное: компилятор не обязан вас спасать. Стандарт прямо говорит: no diagnostic required. То есть можно написать код, который формально нарушает правило, а компилятор спокойно промолчит.
Для проверки можно использовать clang-tidy с bugprone-reserved-identifier: он как раз ищет использование идентификаторов, зарезервированных для реализации, включая Name, глобальные name и __ внутри C++-идентификаторов.
А как делают большие проекты?
Google C++ Style Guide использует snake_case для переменных, а для data members классов — trailing underscore: table_name_. При этом поля struct называются как обычные переменные, без суффикса.
Chromium в целом следует Google C++ Style Guide, если в собственном гайде не указаны исключения.
LLVM использует CamelCase-подход: переменные должны быть существительными и начинаться с заглавной буквы, функции — с маленькой; для STL-подобных классов допускаются имена в стиле стандартной библиотеки.
C++ Core Guidelines не пытаются узаконить единственный стиль. Там прямо признаётся, что naming/layout часто субъективны, но всё равно предлагаются дефолтные правила: использовать единый стиль, предпочитать underscore_style, а ALL_CAPS оставлять только для макросов.
Boost рекомендует имена в нижнем регистре с подчёркиваниями, а макросы — в верхнем регистре с префиксом BOOST_.
Mozilla использует систему префиксов: m для member, s для static member, g для global, a для argument, k для constant; макросы начинаются с MOZ_.
Qt Creator использует m_ для members, но делает исключения для d и q pointers, связанных с d-pointer/pimpl-паттерном. Сам d-pointer в Qt используется для сокрытия деталей реализации и сохранения бинарной совместимости библиотек.
Что с _member в реальных проектах?
Такой стиль существует. Иногда он встречается даже в крупных и известных кодовых базах. Например, в Telegram Desktop можно встретить private members с leading underscore вроде lastUpdate, sets, _owner и так далее.
Заключение
В С++ полноподводных камней и нейминг переменных одно из них. Лично мне больше нравится STL или Boost‑like нейминг, то есть снейк кейс и придерживаюсь того, что нижнее подчеркивание и далее название переменной — плохая практика. А что думаете вы?




















