Вход/Регистрация
Стандарты программирования на С++. 101 правило и рекомендация
вернуться

Александреску Андрей

Шрифт:

class Port {

public:

 Port(const string& destination); // Вызов OpenPort

 ~Port; // вызов ClosePort

 // Порты обычно не клонируются, так что запрещаем

 // копирование и присваивание

};

void DoSomething {

 Port port1("server1:80");

 // ...

} // Забыть закрыть порт нельзя - он будет закрыт

// автоматически при выходе из области видимости

shared_ptr<Port> port2 =/*...*/; // port2 будет закрыт

// автоматически, когда будет уничтожен последний

// ссылающийся на него объект shared_ptr

Вы можете также использовать библиотеки, которые реализуют соответствующий шаблон проектирования (см. [Alexandrescu00c]).

При реализации идиомы RAII следует особо тщательно подходить к вопросу о копирующем конструкторе и присваивании (см. рекомендацию 49): обычно генерируемые компилятором версии этих функций не подходят. Если копирование лишено смысла, копирующий конструктор и оператор присваивания можно явным образом запретить, делая их закрытыми членами и не определяя (см. рекомендацию 53). В противном случае копирующий конструктор дублирует ресурс или использует счетчик ссылок на него, и то же делает и оператор присваивания, при необходимости освободив ресурс, которым объект владел до присваивания. Классической ошибкой является освобождение старого ресурса до того, как успешно дублирован новый (см. рекомендацию 71).

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

new
) в отдельной инструкции, которая тут же передает ресурс управляющему объекту (например,
shared_ptr
). В противном случае может возникнуть утечка ресурсов, связанная с тем, что порядок вычисления параметров функции не определен (см. рекомендацию 31). Например:

void Fun(shared_ptr<Widget> sp1, shared_ptr<Widget> sp2);

// ...

Fun(shared_ptr<Widget>(new Widget),

shared_ptr<Widget>(new Widget));

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

new
), а уже затем будут вызваны два конструктора
Widget
. Такая последовательность действий может привести к утечке: если один из конструкторов сгенерирует исключение, то память для другого объекта никогда не будет освобождена (более детальную информацию по этому вопросу вы найдете в [Sutter02]).

Эта тонкая проблема имеет простое решение: следуйте приведенному выше совету и никогда не выделяйте в одной инструкции больше одного ресурса. Следует выполнять каждое явное выделение ресурса (например,

new
) в отдельной инструкции, которая тут же передает ресурс управляющему объекту (например,
shared_ptr
), например:

shared_ptr<Widget> sp1(new widget), sp2(new Widget);

Fun(sp1, sp2);

См. также описание дополнительных преимуществ такого стиля в рекомендации 31.

Исключения

Можно чересчур увлечься интеллектуальными указателями. Обычные указатели вполне подходят для кода, в котором указываемый объект виден только в ограниченном объеме (например, внутри класса — типа указателя на узел дерева в классе

Tree
, использующийся для навигации по дереву).

Ссылки

[Alexandrescu00c] • [Cline99] §31.03-05 • [Dewhurst03] §24, §67 • [Meyers96] §9-10 • [Mitewski01] • [Stroustrup00] §14.3-4, §25.7, §E.3, §E.6 • [Sutter00] §16 • [Sutter02] §20-21 • [Vandevoorde03] §20.1.4

Стиль кодирования

Константа для одного является переменной для другого.

— Алан Перлис (Alan Perlis)

В этом разделе мы перейдем от вопросов проектирования к вопросам, которые появляются в основном при реальном кодировании.

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

В этом разделе мы считаем наиболее важной рекомендацию 14: "Предпочитайте ошибки компиляции и компоновки ошибкам времени выполнения".

14. Предпочитайте ошибки компиляции и компоновки ошибкам времени выполнения

Резюме

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

  • Читать дальше
  • 1
  • ...
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: