[Перевод] Руководство Google по стилю в C++. Часть 6

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

Часть 5. Функции
Часть 6. Специфика Google

xwiwgvrv9mtijocibex24w3tgu8.jpeg

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

Специфика Google


Есть различные трюки и средства, которые используются чтобы сделать код на C++ более надёжным. И да, они могут отличаться от того, что используют в других компаниях.

Владение и умные указатели


Предпочтительно, чтобы динамически созданный объект имел одного (выделенного) владельца. Передачу такого «владения» желательно проводить через умные указатели.

Определение
«Владение» это технология учёта, используемая для управления динамически выделенной памятью или другими ресурсами. Владелец динамической сущности (объекта) это объект или функция, которые ответственны за удаление сущности, когда она будет не нужна. Владение может быть распределённым, и в этом случае обычно последний оставшийся владелец отвечает за удаление. Даже если владение не является распределённым, этот механизм может использоваться, чтобы передать владение от одного объекта (или кода) другому.

«Умные» указатели это классы, которые функционируют как обычные указатели; например, в них перегружены операторы * и . Некоторые типы умных указателей можно использовать для автоматического управления «владением»: учёт владельцев, удаление объектов. std: unique_ptr это умный указатель, добавленный в C++11, который реализует эксклюзивное владение (только один владелец); объект удаляется в случае выхода из области видимости экземпляра std: unique_ptr. std: unique_ptr не может быть скопирован, однако его можно передать (move) другому std: unique_ptr, что фактически есть передача владения. std: shared_ptr это умный указатель, реализующий распределённое владение. std: shared_ptr можно копировать, при этом владение распределяется между всеми копиями. Управляемый объект удаляется, когда разрушается последняя копия std: shared_ptr.

За

  • Очень тяжело управлять динамической памятью без какого-либо механизма учёта владения.
  • Передача владения может быть проще и быстрее, чем копирование объекта. Также не все объекты можно скопировать.
  • Передача владения может быть проще, чем копирование указателя или использование ссылок, т.к. нет необходимости согласовывать жизненный цикл объекта между различными частями кода.
  • Умные указатели могут улучшить читабельность кода, сделать его логику более понятной, самодокументируемой и непротиворечивой.
  • Умные указатели могут исключить ручное управление владением, упростить код и избежать большого количества ошибок.
  • Для константных объектов распределённое владение может быть простой и эффективной альтернативой против полного копирования.

Против

  • Владение должно представляться и передаваться через указатели (любо умные, либо обычные). Семантика указателей сложнее работы со значениями, особенно в API: помимо владения необходимо беспокоиться о правильности используемых типов (aliasing), времени жизни, изменяемости объектов и т.д.
  • Затраты по производительности при копировании значений часто завышены, поэтому прирост производительности при передаче владения (против простого копирования) в ряде случаев не может оправдать ухудшение читабельности и увеличение сложности кода.
  • API управления владением могут накладывать свои ограничения на модель (порядок) управления памятью.
  • При использовании умных указателей нет чёткого понимания где именно (в коде) будет производится освобождение ресурсов.
  • std: unique_ptr реализует передачу владения через семантику перемещения C++11, которая является новой и может затруднить понимание кода.
  • Распределённое владение с одной стороны позволяет аккуратно управлять владением, с другой стороны может усложнить архитектуру системы.
  • Распределённое владение требует операций учёта во время выполнения, это может отразиться на производительности.
  • В ряде случаев (например, создании циклических ссылок) объекты с распределённым владением никогда не удалятся.
  • Умные указатели не всегда могут заменить обычные указатели.

Вердикт
Если необходима работа с динамической памятью, то предпочтительно чтобы код, выделяющий память, ею же и владел. Если другой код хочет получить доступ к этой памяти, то можно передать копию, указатель или ссылку (и всё это без передачи владения). Предпочтительно использовать std: unique_ptr для явной передачи владения. Например:

std::unique_ptr FooFactory();
void FooConsumer(std::unique_ptr ptr);


Без существенной причины не проектируйте (не используйте) код с распределённым владением. Как вариант, это может быть желание избежать «тяжелой» операции копирования, однако обязательно убедитесь, что выигрыш будет существенным и разделяемый объект — неизменяемый (т.е. std: shared_ptr). Если же требуется именно распределённое владение, то используйте std: shared_ptr.
Никогда не используйте std: auto_ptr. В качестве замены есть std: unique_ptr.

cpplint


Для проверки кода на ошибки стиля используйте cpplint.py.

cpplint.py — утилита, которая читает файл с кодом и определяет многие ошибки в стиле. Конечно, она не идеальна, иногда выдаёт ложно-положительные и ложно-отрицательные ошибки, однако это всё равно полезная утилита. Ложно-положительные ошибки можно исключить, если вставлять // NOLINT в конце строчки кода или // NOLINTNEXTLINE на предыдущей строке.

Иногда в проекте есть инструкция, откуда брать и как пользоваться cpplint.py. Если в вашем проекте такой нет, то можно просто скачать cpplint.py.


Примечания:
Изображение взято из открытого источника.

© Habrahabr.ru