Готовый перевод Google C++ Style Guide / Google C++ Style Guide: Scoping

Внимание! Этот перевод, возможно, ещё не готов, так как модераторы установили для него статус «идёт перевод»

Области видимости

Пространства имен

безымянные пространства имен поддерживаются в файлах .сс . Для имен лучше выбирать название, основанное на проекте, и, желательно, его путь. Не используйте директиву using.

Определение:

Пространства имен подразделяют глобальную область действия на отдельные, называемые областями действия, и они полезны для предотвращения именного конфликта в глобальной области.

Плюсы:

Пространства имен предоставляют (иерархическую) ось присваивания имен, кроме (также иерархической) оси, предоставляемой классами.

Например, если два разных проекта имеют класс Foo в глобальной области, эти символы могут конфликтовать во время компиляции либо во время исполнения программы. Если каждый проект расположит их код в пространстве имен, то проект1::Foo и проект2::Foo теперь являются отдельными символами, которые не конфликтуют.

Минусы:

Пространства имен могут запутаться, потому что они предоставляют дополнительную (иерархическую) ось именования, в дополнение к оси именования, предоставляемой классами.

Использование безымянных пространств имен в файлах заголовков могут легко нарушить правило одного описания (ODR)

Вывод:

Используйте пространства имен в соответствии с методикой, описанной ниже. Завершайте пространства имен комментариями, которые показаны в примерах.

Безымянные пространства имен

Безымянные пространства имен допустимы и даже поддерживаются в файлах .сс чтобы избежать именные конфликты во время исполнения:

Однако, описания области действия файлов, которые связаны с индивидуальными классами, могут быть объявлены в этих классах как типы, статические переменные-члены класса или статические функции-члены класса скорее чем в качестве членов безымянных пространств имен.

Не используйте безымянные пространства имен в файлах .h

Именные пространства имен

Именные пространства имен должны быть использованы следующим образом:

Пространства имен охватывают весь исходный файл после включений, определений/объявлений флажков, и отправляют объявления классов из остальных пространств имен:

Не объявляйте ничего в namespace std, даже не посылайте объявления стандартной библиотеки классов. Объявляемые модули в namespace std - неопределенные характеристики, то есть недоступны. Чтобы объявить модули из стандартной библиотеки, включите соответствующий файл заголовка.

Вы можете не использовать using-директиву чтобы сделать все имена из пространства имен доступными.

Вы можете использовать using-объявление где угодно в файле .сс и в функциях, методах или классах в файлах .h

Псевдонимы пространства имен допустимы везде в файлах .сс, везде внутри именного пространства имен, охватывающего весь файл .h, функции и методы.

Отметьте, что псевдоним в .h файле видим всем файлам, которые его включают, так публичные заголовки (доступные вне проекта) и заголовки, транзитивно включенные ими, должны избегать определения псевдонима для выполнения главной цели – сохранить API ограниченным, насколько это возможно.

Вложенные классы

Не смотря на то, что Вы можете использовать публичные вложенные классы, когда они являются частью интерфейса, полагают, что пространство имен не допускает их объявления в глобальной области видимости.

Определение:

Класс может определять другой класс внутри себя; этот класс так же будет называться членом класса.

Плюсы:

Это полезно когда внутренний (или член) класс используется только в охватывающем классе; создание этого члена вводит его в область видимости охватывающего класса, что не загрязняет окружающую область видимости именем класса. Вложенные классы могут иметь дальнее определение внутри охватывающего класса и потом быть определенными в .cc файле, избегая включения определения вложенного класса в определении охватывающего класса, т.к. вложенное определение класса, как правило, относится только к реализации.

Минусы:

Вложенные классы могут быть предварительно объявлены только внутри определения охватывающего класса. Таким образом, любой заголовочный файл, использующий указатель Foo::Bar* должен включать полное объявление класса Foo.

Заключение:

Не делайте вложенные классы открытыми (спецификатор доступа public), пока они являются частью интерфейса, например, класс который содержит набор опций для некоторого метода.

Неклассовые и статичные поля и глобальные функции.

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

Плюсы:

Не являющиеся членами и статические члены функции могут быть полезными в некоторых ситуациях. Помещение функций, не являющимися членами класса, в пространство имен позволяет избежать загрязнения глобального пространства имен.

Минусы:

Функции, не являющиеся членом, и статические члены функции могут иметь больше смысла как члены нового класса, особенно если они получают доступ к внешним ресурсам или имеют существенные зависимости.

Решение:

Иногда полезно, или даже необходимо, определить функцию, не связанную с экземпляром класса. Такая функция может быть или статическим членом или функцией, не являющейся членом. Функции, не являющиеся членом, не должны зависеть от внешних переменных и должны почти всегда существовать в пространстве имен. Вместо того чтобы создавать классы только для того, чтобы сгруппировать статические функции, которые не используют общие статические данные, используйте пространства имен.

Функции, определяемые в той же единице компиляции, что и классы могут ввести ненужные зависимости связанности и линковки при непосредственном вызове другими единицами компиляции; статические члены функции особенно восприимчивы к этому. Рассмотрите разработку нового класса или размещение функций в пространстве имен возможно в отдельной библиотеке.

Если Вы должны определить функцию, не являющуюся членом, и она необходима только в .cc файле, используйте неименованное пространство имен или статическую линковку (например, static int Foo() {...}), чтобы ограничить ее видимость.

Локальные переменные

Располагайте переменные функции в наиболее узкую область видимости, и инициализируйте переменные в объявлении.

C++ позволяет объявлять переменные где угодно в функции. Мы советуем Вам объявлять их в максимально локальной области видимости, и максимально близко к первому использованию. Это упрощает для читателя находить объявление и видеть каким типом является переменная, и чем она проинициализирована. В частности, инициализация должна использоваться вместо объявления и присваивания, например:

Следует отметить, что GCC реализует for (int i = 0; i < 10; ++i) правильно (область видимости i является только область видимости цикла for), так что затем можно использовать i в другом цикле в той же области видимости. Это также правильно для областей видимости операторов if и while, например,

Существует один нюанс: если переменная является объектом, его конструктор вызывается каждый раз, как переменная входит в область видимости и объект создается, а его деструктор вызывается каждый раз, когда она выходит из области видимости.

Может быть более эффективно, объявить такую​ ​переменную, используемую в цикле за пределами этого цикла:

Статические и глобальные переменные

Статические или глобальные переменные классов запрещены: из-за отсутствия определённости в конструкторе и деструкторе они становятся причинами ошибок, которые сложно найти.

Объекты со статичным размером данных, включая глобальные переменные, статичные переменные, статичные поля классов и статичные переменные функций, должны быть Plain Old Data (POD): только int, char, float, указатели или массивы/структуры POD.

Порядок, в котором конструкторы класса и инициализаторы статичных переменных должны вызываться, лишь частично описан в C++ и может меняться от сборки к сборке, что может послужить причиной ошибок, которые сложно найти. Так что, в довесок к запрету глобальных переменных типа класс, мы не разрешаем инициализацию статичных POD-переменных с помощью результата функции, если только эта функция (например, getenv() или getpid()) сама не зависит от любых других глобальных переменных.

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

Таким образом, мы разрешаем использование лишь тех статичных переменных, что содержат POD-данные. Это правило полностью запрещает использование vector и string, вместо которых рекомендуется использовать массивы C и const char [] соответственно.

Если вам требуется статическая или глобальная переменная типа класса, инициализируйте указатель (которые никогда не должен быть освобожден), из функции main() или pthread_once(). Следует отметить, что это не должен быть "умный" указатель. Используя "умный" указатель, можно столкнуться с проблемой последовательности вызова деструкторов, чего следует избегать.

Внимание! Этот перевод, возможно, ещё не готов.
Его статус: идёт перевод

Переведено на Нотабеноиде
http://notabenoid.org/book/32830/114722

Переводчики: Nuriya94, Draks, aereiae, Andersen1313

xmorph, flyngate, lyzov

Настройки

Готово:

100.00% КП = 1.1