27 November 2019

Руководство Google по стилю в C++. Часть 8

C++
Sandbox
Часть 1. Вступление

Часть 8. Именование
Часть 9. Комментарии




Все мы при написании кода пользуемся правилами оформления кода. Иногда изобретаются свои правила, в других случаях используются готовые стайлгайды. Хотя все C++ программисты читают на английском легче, чем на родном, приятнее иметь руководство на последнем.
Эта статья является переводом части руководства Google по стилю в C++ на русский язык.
Исходная статья (fork на github), обновляемый перевод.

Именование


Основные правила стиля кодирования приходятся на именование. Вид имени сразу же (без поиска объявления) говорит нам что это: тип, переменная, функция, константа, макрос и т.д. Правила именования могут быть произвольными, однако важна их согласованность, и правилам нужно следовать.

Общие принципы именования


  • Используйте имена, который будут понятны даже людям из другой команды.
  • Имя должно говорить о цели или применимости объекта.
  • Не экономьте на длине имени, лучше более длинное и более понятное (даже новичкам) имя.
  • Поменьше аббревиатур, особенно если они незнакомы вне проекта.
  • Используйте только известные аббревиатуры (Википедия о них знает?).
  • Не сокращайте слова.

В целом, длина имени должна соответствовать размеру области видимости. Например, n — подходящее имя внутри функции в 5 строк, однако при описании класса это может быть коротковато.

class MyClass {
 public:
  int CountFooErrors(const std::vector<Foo>& foos) {
    int n = 0;  // Чёткий смысл для небольшой области видимости
    for (const auto& foo : foos) {
      ...
      ++n;
    }
    return n;
  }
  void DoSomethingImportant() {
    std::string fqdn = ...;  // Известная аббревиатура полного доменного имени
  }
 private:
  const int kMaxAllowedConnections = ...;  // Чёткий смысл для контекста
};

class MyClass {
 public:
  int CountFooErrors(const std::vector<Foo>& foos) {
    int total_number_of_foo_errors = 0;  // Слишком подробное имя для короткой функции
    for (int foo_index = 0; foo_index < foos.size(); ++foo_index) {  // Лучше использовать `i`
      ...
      ++total_number_of_foo_errors;
    }
    return total_number_of_foo_errors;
  }
  void DoSomethingImportant() {
    int cstmr_id = ...;  // Сокращённое слово (удалены буквы)
  }
 private:
  const int kNum = ...;  // Для целого класса очень нечёткое имя
};

Отметим, что типовые имена также допустимы: i для итератора или счётчика, T для параметра шаблона.

В дальнейшем при описании правил «word» / «слово» это всё, что пишется на английском без пробелов, в том числе и аббревиатуры. В слове первая буква может быть заглавной (зависит от стиля: "camel case" или «Pascal case»), остальные буквы — строчные. Например, предпочтительно StartRpc(), нежелательно StartRPC().

Параметры шаблона также следуют правилам своих категорий: Имена типов, Имена переменных и т.д…

Имена файлов


Имена файлов должны быть записаны только строчными буквами, для разделения можно использовать подчёркивание (_) или дефис (-). Используйте тот разделитель, который используется в проекте. Если единого подхода нет — используйте "_".

Примеры подходящих имён:

  • my_useful_class.cc
  • my-useful-class.cc
  • myusefulclass.cc
  • myusefulclass_test.cc // _unittest and _regtest are deprecated.

C++ файлы должны заканчиваться на .cc, заголовочные — на
.h. Файлы, включаемые как текст должны заканчиваться на .inc (см. также секцию Независимые заголовочники).

Не используйте имена, уже существующие в /usr/include, такие как db.h.

Старайтесь давать файлам специфичные имена. Например, http_server_logs.h лучше чем logs.h. Когда файлы используются парами, лучше давать им одинаковые имена. Например, foo_bar.h и foo_bar.cc (и содержат класс FooBar).

Имена типов


Имена типов начинаются с прописной буквы, каждое новое слово также начинается с прописной буквы. Подчёркивания не используются: MyExcitingClass, MyExcitingEnum.

Имена всех типов — классов, структур, псевдонимов, перечислений, параметров шаблонов — именуются в одинаковом стиле. Имена типов начинаются с прописной буквы, каждое новое слово также начинается с прописной буквы. Подчёркивания не используются. Например:

// classes and structs
class UrlTable { ...
class UrlTableTester { ...
struct UrlTableProperties { ...

// typedefs
typedef hash_map<UrlTableProperties *, std::string> PropertiesMap;

// using aliases
using PropertiesMap = hash_map<UrlTableProperties *, std::string>;

// enums
enum UrlTableErrors { ...

Имена переменных


Имена переменных (включая параметры функций) и членов данных пишутся строчными буквами с подчёркиванием между словами. Члены данных классов (не структур) дополняются подчёркиванием в конце имени. Например: a_local_variable, a_struct_data_member, a_class_data_member_.

Имена обычных переменных


Например:

std::string table_name;  // OK - строчные буквы с подчёркиванием

std::string tableName;   // Плохо - смешанный стиль

Члены данных класса


Члены данных классов, статические и нестатические, именуются как обычные переменные с добавлением подчёркивания в конце.

class TableInfo {
  ...
 private:
  std::string table_name_;  // OK - подчёркивание в конце
  static Pool<TableInfo>* pool_;  // OK.
};

Члены данных структуры


Члены данных структуры, статические и нестатические, именуются как обычные переменные. К ним не добавляется символ подчёркивания в конце.

struct UrlTableProperties {
  std::string name;
  int num_entries;
  static Pool<UrlTableProperties>* pool;
};

См. также Структуры vs Классы, где описано когда использовать структуры, когда классы.

Имена констант


Объекты объявляются как constexpr или const, чтобы значение не менялось в процессе выполнения. Имена констант начинаются с символа «k», далее идёт имя в смешанном стиле (прописные и строчные буквы). Подчёркивание может быть использовано в редких случаях когда прописные буквы не могут использоваться для разделения. Например:

const int kDaysInAWeek = 7;
const int kAndroid8_0_0 = 24;  // Android 8.0.0

Все аналогичные константные объекты со статическим типом хранилища (т.е. статические или глобальные, подробнее тут: Storage Duration) именуются также. Это соглашение является необязательным для переменных в других типах хранилища (например, автоматические константные объекты).

Имена функций


Обычные функции именуются в смешанном стиле (прописные и строчные буквы); функции доступа к переменным (accessor и mutator) должны иметь стиль, похожий на целевую переменную.

Обычно имя функции начинается с прописной буквы и каждое слово в имени пишется с прописной буквы.

void AddTableEntry();
void DeleteUrl();
void OpenFileOrDie();

(Аналогичные правила применяются для констант в области класса или пространства имён (namespace) которые представляют собой часть API и должны выглядеть как функции (и то, что они не функции — некритично))

Accessor-ы и mutator-ы (функции get и set) могут именоваться наподобие соответствующих переменных. Они часто соответствуют реальным переменным-членам, однако это не обязательно. Например, int count() и void set_count(int count).

Именование пространства имён (namespace)


Пространство имён называется строчными буквами. Пространство имён верхнего уровня основывается на имени проекта. Избегайте коллизий ваших имён и других, хорошо известных, пространств имён.

Пространство имён верхнего уровня — это обычно название проекта или команды (которая делала код). Код должен располагаться в директории (или поддиректории) с именем, соответствующим пространству имён.

Не забывайте правило не использовать аббревиатуры — к пространствам имён это также применимо. Коду внутри вряд ли потребуется упоминание пространства имён, поэтому аббревиатуры — это лишнее.

Избегайте использовать для вложенных пространств имён известные названия. Коллизии между именами могут привести к сюрпризам при сборке. В частности, не создавайте вложенных пространств имён с именем std. Рекомендуются уникальные идентификаторы проекта (websearch::index, websearch::index_util) вместо небезопасных к коллизиям websearch::util.

Для internal / внутренних пространств имён коллизии могут возникать при добавлении другого кода (внутренние хелперы имеют свойство повторяться у разных команд). В этом случае хорошо помогает использование имени файла для именования пространства имён. (websearch::index::frobber_internal для использования в frobber.h)

Имена перечислений


Перечисления (как с ограничениями на область видимости (scoped), так и без (unscoped)) должны именоваться либо как константы, либо как макросы. Т.е.: либо kEnumName, либо ENUM_NAME.

Предпочтительно именовать отдельные значения в перечислителе как константы. Однако, допустимо именовать как макросы. Имя самого перечисления UrlTableErrorsAlternateUrlTableErrors), это тип. Следовательно, используется смешанный стиль.

enum UrlTableErrors {
  kOk = 0,
  kErrorOutOfMemory,
  kErrorMalformedInput,
};
enum AlternateUrlTableErrors {
  OK = 0,
  OUT_OF_MEMORY = 1,
  MALFORMED_INPUT = 2,
};

Вплоть до января 2009 года стиль именования значений перечисления был как у макросов. Это создавало проблемы дублирования имён макросов и значений перечислений. Применение стиля констант решает проблему и в новом коде предпочтительно использовать стиль констант. Однако, старый код нет необходимости переписывать (пока нет проблем дублирования).

Имена макросов


Вы ведь не собираетесь определять макросы? На всякий случай (если собираетесь), они должны выглядеть так:
MY_MACRO_THAT_SCARES_SMALL_CHILDREN_AND_ADULTS_ALIKE.

Пожалуйста прочтите как определять макросы; Обычно, макросы не должны использоваться. Однако, если они вам абсолютно необходимы, именуйте их прописными буквами с символами подчёркивания.

#define ROUND(x) ...
#define PI_ROUNDED 3.0

Исключения из правил именования


Если вам нужно именовать что-то, имеющее аналоги в существующем C или C++ коде, то следуйте используемому в коде стилю.

bigopen()
имя функции, образованное от open()

uint
определение, похожее на стандартные типы

bigpos
struct или class, образованный от pos

sparse_hash_map
STL-подобная сущность; следуйте стилю STL

LONGLONG_MAX
константа, такая же как INT_MAX

Прим.: ссылки могут вести на ещё не переведённые разделы руководства.
Tags:C++styleguideперевод с английского
Hubs: C++
+10
14.2k 107
Comments 21
Popular right now
Разработчик С/C++
from 80,000 ₽EltexНовосибирск
C++ Developer
from 130,000 to 180,000 ₽QuadcodeСанкт-Петербург
Разработчик C++
from 90,000 ₽ТакскомМосква
Разработчик С /С++
from 110,000 ₽VMS SoftwareСанкт-ПетербургRemote job
C++ разработчик
from 80,000 ₽TRUSTSOFTКраснодар