Теперь вам необходимо быть более осторожным, так как вы заранее не знаете тип целевого объекта. Например, разве можно быть уверенным, что оператор T::operator=
try
.try {
copy(buf_, buf_+msgSize_, p);
copy(data, data+len, p+msgSize_);
} catch(...) {
// He имеет значения, какое исключение выбрасывается; все, что
delete[] p; // мне необходимо сделать - это подчистить за собой,
throw; // а затем повторно выбросить исключение.
}
Поскольку оператор catch
T::operator=
вы его перехватите и сможете освободить динамическую память, которая была только что распределена.Строго говоря, функция copy
T::operator=
. Это происходит из-за того, что функция copy
и остальные алгоритмы стандартной библиотеки в целом являются нейтральными по отношению к исключениям; это значит, что при выбрасывании исключений во время выполнения каких-либо внутренних операторов это исключение будет передано вызывающей программе, а не будет обработано полностью (перехвачено в блоке catch
без повторного выбрасывания этого исключения). Это сохраняет возможность перехвата исключений в блоке catch
, выполнения некоторой подчистки с последующим их повторным выбрасываний, но в конце концов все исключения, выброшенные в классе или функции стандартной библиотеки, дойдут до вызывающей программы.Создание безопасных при исключениях функций-членов — трудоемкая работа. Для этого вам необходимо выявить все места, где могут выбрасываться исключения, и убедиться, что вы правильно их обрабатываете. Когда исключение может выбрасываться? При любом вызове функции. Операторы для встроенных типов данных не могут выбрасывать исключения, а деструкторы
Наконец, как и для большинства других требований, предъявляемых к программному обеспечению, вам требуется обеспечить только тот уровень безопасности исключений, который вам необходим. Другими словами, если вы создаете диалоговый мастер по генерации веб-страниц, график вашей разработки, вероятно, не позволит провести необходимое исследование и тестирование обеспечения в нем строгой безопасности исключений. Так, для вашего заказчика может быть приемлемой ситуация, когда пользователи встречаются иногда с сообщением о неопределенной ошибке: «Неизвестная ошибка, аварийное завершение программы» («Unknown error, aborting»). С другой стороны, если вы создаете программное обеспечение для управления углом ротора вертолета, ваш заказчик, вероятно, будет настаивать на обеспечении более существенных гарантий безопасности, чем вывод сообщения «Неизвестная ошибка, аварийное завершение программы».
9.5. Безопасное копирование объекта
Требуется иметь безопасные при исключениях конструктор копирования и оператор присваивания базового класса.
Примените тактику, предложенную в рецепте 9.4, а именно сначала выполните все действия, которые могут выбрасывать исключения, и изменяйте состояние объектов с помощью операций, которые не могут выбрасывать исключения только после того, как будет завершена вся опасная работа. В примере 9.6 вновь представлен класс Message
#include
#include
const static int DEFAULT_BUF_SIZE = 3;
const Static int MAX_SIZE = 4096;
class Message {
public:
Message(int bufSize = DEFAULT_BUF_SIZE) :
bufSize_(bufSize), initBufSize_(bufSize), msgSize_(0), key_("") {