Читаем C++. Сборник рецептов полностью

   throw; // тела конструктора

  }

Режим работы блоков try и catch вполне ожидаем; единственное синтаксическое отличие от обычного блока try заключается в том, что при перехвате исключений, выброшенных из списка инициализации, за ключевым словом try идет двоеточие, затем список инициализации и после этого собственно блок try, который является одновременно и телом конструктора. Если какое-нибудь исключение выбрасывается из списка инициализации или из тела конструктора, оно будет перехвачено catch-обработчиком, который расположен после тела конструктора. Вы можете при необходимости добавить в тело конструктора дополнительную пару блоков try/catch, однако вложенные блоки try/catch обычно выглядят непривлекательно.

Кроме перемещения операторов инициализации членов в список инициализации пример 9.3 отличается от примера 9.2 еще одним свойством. Объекты-члены Device на этот раз не создаются в динамической памяти с помощью оператора new. Я сделал это для иллюстрации двух особенностей, связанных с безопасностью и применением объектов-членов.

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

Но, возможно, вам требуется иметь члены, использующие динамическую память (или с ними вы предпочитаете иметь дело). Рассмотрим подход, используемый в первоначальном классе Broker в примере 9.2. Вы можете просто инициализировать ваши указатели в списке инициализации, не так ли?

class BrokerBad {

public:

 BrokerBad(int devno1, int devno2)

  try : dev1_(new Device(devno1)), // Создать объекты динамической

   dev2_(new Device(devno2)) {}    // памяти в списке инициализации

  catch (...) {

   if (dev1_) {

    delete dev1_; // He должно компилироваться и

    delete dev2_; // является плохим решением, если

   }              // все же будет откомпилировано

   throw; // Повторное выбрасывание того же самого исключения

  }

 ~BrokerBad() {

  delete dev1_;

  delete dev2_;

 }

private:

 BrokerBad();

 Device* dev1_;

 Device* dev2_;

};

Нет, так делать нельзя. Здесь две проблемы. Прежде всего, это не допустит ваш компилятор, потому что расположенный в конструкторе блок catch не должен позволить программному коду получить доступ к переменным-членам, так как их еще нет. Во-вторых, даже если ваш компилятор позволяет это делать, это будет плохим решением. Рассмотрим ситуацию, когда при конструировании объекта dev1_ выбрасывается исключение. Ниже дается программный код, который будет выполняться в catch-обработчике.

catch (...) {

 if (dev1_) { // Какое значение имеет эта переменная?

  delete dev1_; // в данном случае вы удаляете неопределенное значение

  delete dev2_;

 }

 throw; // Повторное выбрасывание того же самого исключения

}

Если исключение выбрасывается в ходе конструирования dev1_, то оператором new не может быть возвращен адрес нового выделенного участка памяти и значение dev1_ не меняется. Тогда что эта переменная содержит? Она будет иметь неопределённое значение, так как она никогда не инициализировалась. В результате, когда вы станете выполнять оператор delete dev1_, вы, вероятно, попытаетесь удалить объект, используя недостоверный адрес, что приведет к краху программы, вы будете уволены, и вам придется жить с этим позором всю оставшуюся жизнь.

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

BrokerBetter(int devno1, int devno2) :

 dev1_(NULL), dev2_(NULL) {

  try {

   dev1_ = new Device(devno1);

   dev2_ = new Device(devno2);

Перейти на страницу:

Похожие книги

1С: Бухгалтерия 8 с нуля
1С: Бухгалтерия 8 с нуля

Книга содержит полное описание приемов и методов работы с программой 1С:Бухгалтерия 8. Рассматривается автоматизация всех основных участков бухгалтерии: учет наличных и безналичных денежных средств, основных средств и НМА, прихода и расхода товарно-материальных ценностей, зарплаты, производства. Описано, как вводить исходные данные, заполнять справочники и каталоги, работать с первичными документами, проводить их по учету, формировать разнообразные отчеты, выводить данные на печать, настраивать программу и использовать ее сервисные функции. Каждый урок содержит подробное описание рассматриваемой темы с детальным разбором и иллюстрированием всех этапов.Для широкого круга пользователей.

Алексей Анатольевич Гладкий

Программирование, программы, базы данных / Программное обеспечение / Бухучет и аудит / Финансы и бизнес / Книги по IT / Словари и Энциклопедии
1С: Управление торговлей 8.2
1С: Управление торговлей 8.2

Современные торговые предприятия предлагают своим клиентам широчайший ассортимент товаров, который исчисляется тысячами и десятками тысяч наименований. Причем многие позиции могут реализовываться на разных условиях: предоплата, отсрочка платежи, скидка, наценка, объем партии, и т.д. Клиенты зачастую делятся на категории – VIP-клиент, обычный клиент, постоянный клиент, мелкооптовый клиент, и т.д. Товарные позиции могут комплектоваться и разукомплектовываться, многие товары подлежат обязательной сертификации и гигиеническим исследованиям, некондиционные позиции необходимо списывать, на складах периодически должна проводиться инвентаризация, каждая компания должна иметь свою маркетинговую политику и т.д., вообщем – современное торговое предприятие представляет живой организм, находящийся в постоянном движении.Очевидно, что вся эта кипучая деятельность требует автоматизации. Для решения этой задачи существуют специальные программные средства, и в этой книге мы познакомим вам с самым популярным продуктом, предназначенным для автоматизации деятельности торгового предприятия – «1С Управление торговлей», которое реализовано на новейшей технологической платформе версии 1С 8.2.

Алексей Анатольевич Гладкий

Финансы / Программирование, программы, базы данных