Д. Стефенс - C++. Сборник рецептов
- Название:C++. Сборник рецептов
- Автор:
- Жанр:
- Издательство:КУДИЦ-ПРЕСС
- Год:2007
- Город:Москва
- ISBN:5-91136-030-6
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Д. Стефенс - C++. Сборник рецептов краткое содержание
Данная книга написана экспертами по C++ и содержит готовые рецепты решения каждодневных задач для программистов на С++. Один из авторов является создателем библиотеки Boost Iostreams и нескольких других библиотек C++ с открытым исходным кодом. В книге затрагивается множество тем, вот лишь некоторые из них: работа с датой и временем; потоковый ввод/вывод; обработка исключений; работа с классами и объектами; сборка приложений; синтаксический анализ XML-документов; программирование математических задач. Читатель сможет использовать готовые решения, а сэкономленное время и усилия направить на решение конкретных задач.
C++. Сборник рецептов - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Это покрывает ограниченный набор исключительных ситуаций, и, вероятно, стандартные классы исключений имеют не все, что вам нужно. По-видимому, вам потребуется иметь исключения, более ориентированные на конкретные приложения, например database_error
, network_error
, painting_error
и т.п. Мы обсудим это позже. А до этого давайте рассмотрим, как работают стандартные исключения.
Поскольку стандартная библиотека использует стандартные классы исключений (допустим это), можно ожидать, что классы из стандартной библиотеки будут их выбрасывать при возникновении проблемной ситуации, например при попытке использовать индекс, выходящий за пределы диапазона вектора vector
.
std::vector v;
int i = -1;
// заполнить вектор v...
try {
i = v.at(v.size()); // Выход на один элемент за конец вектора
} catch (std::out_of_range& е) {
std::cerr << "Whoa, exception thrown: " << e.what() << '\n';
}
vector<>::at
выбросит исключение out_of_range
, если вы используете индекс, значение которого меньше или больше, чем size() - 1
. Поскольку вам это известно, вы можете написать обработчик, специально предназначенный для этой исключительной ситуации. Если вам не требуется обрабатывать отдельно конкретный тип исключения, а вместо этого вы предпочли бы одинаково обрабатывать все исключения, вы можете перехватить базовый класс всех исключений.
catch(std::exception& е) {
std::cerr << "Nonspecific exception: " << e.what() << '\n';
}
В результате будет перехватываться любой класс, производный от exception
, what
— это виртуальная функция-член, которая выдает строку сообщения, зависящую от реализации.
Я почти вернулся в исходную точку. Цель примера 9.1, который сопровождается продолжительным обсуждением, — иллюстрация достоинств класса исключения. Две вещи делают класс исключения полезным: иерархия, отражающая природу исключения, и сообщение, выдаваемое при перехвате исключения и предназначенное для пользователей программы. Иерархия классов исключений позволит разработчикам, использующим вашу библиотеку, создавать безопасный программный код и легко его отлаживать, а текст сообщения позволит тем же самым разработчикам предоставлять конечным пользователям приложения осмысленное сообщение об ошибке.
Исключения представляют собой сложную тему, и безопасная и эффективная обработка исключительных ситуаций является одной из самых трудных задач в проектировании программного обеспечения в целом и на языке C++ в частности. Каким должен быть конструктор, который не приведет к утечке памяти, если исключение выбрасывается в его теле или в списке инициализации? Что такое безопасное исключение? Я отвечу на эти и другие вопросы в последующих рецептах.
9.2. Создание безопасного при исключениях конструктора
Ваш конструктор должен обеспечить базовые и строгие гарантии безопасности исключений. См. обсуждение, которое следует за определением «базовых» и «строгих» гарантий.
Используйте в конструкторе блоки try
и catch
, чтобы правильно завершить действия по очистке объекта, если в ходе конструирования выбрасывается исключение. В примере 9.2 приводятся простые классы Device
и Broker
. Broker
создает два объекта Device
в динамической памяти ( heap
), но он должен правильно очистить память от этих объектов, если при конструировании выбрасывается исключение.
Пример 9.2. Безопасный при исключениях конструктор
#include
#include
using namespace std;
class Device {
public:
Device(int devno) {
if (devno == 2)
throw runtime_error("Big problem");
}
~Device() {}
};
class Broker {
public:
Broker (int devno1, int devno2) : dev1_(NULL), dev2_(NULL) {
try {
dev1_ = new Device(devno1); // Заключить операторы создания
dev2_ = new Device(devno2); // объектов в динамической памяти в
// блок try ...
} catch (...) {
delete dev1_; // ...очистить память и повторно
throw; // выбросить исключение, если что-то не
// получилось.
}
}
~Broker() {
delete dev1_;
delete dev2_;
}
private:
Broker();
Device* dev1_;
Device* dev2_;
};
int main() {
try {
Broker b(1, 2);
} catch(exception& e) {
cerr << "Exception: " << e.what() << endl;
}
}
Сказать, что конструктор, функция-член, деструктор или что-нибудь другое «безопасно при исключениях», — значит гарантировать, что при их работе не будет утечки ресурсов и, вероятно, используемые ими объекты не будут находиться в противоречивом состоянии. В языке C++ такого рода гарантии названы базовыми и строгими .
Базовая гарантия безопасности при исключениях, которая интуитивно вполне понятна, означает, что при выбрасывании исключения текущая операция не приведет к утечке ресурсов и вовлеченный в операцию объект по-прежнему можно использовать (т.е. вы можете вызвать другие функции-члены и уничтожить объект, так как его состояние корректно). Это также означает, что программа находится в согласованном состоянии, хотя оно может быть непредсказуемым. Правила простые: если исключение выбрасывается где-нибудь в теле (например) функции-члена, созданные в динамической памяти объекты не лишаются поддержки, а вовлеченные в операцию объекты могут быть уничтожены или восстановлены в вызывающей программе. Другая гарантия, названная строгой гарантией безопасности исключений, обеспечивает неизменность состояния объекта, если операция завершается неудачно. Последнее относится к операциям, которые следуют после конструирования объекта, поскольку по определению объект, который выбрасывает исключение, всегда будет сконструирован не полностью и поэтому всегда будет иметь недостоверное состояние. Я вернусь к функциям-членам в рецепте 9.4. Теперь же давайте основное внимание уделим конструированию объектов.
В примере 9.2 определяется два класса, Device
и Broker
, которые делают не очень много, но с их помощью можно было бы легко представить любой сценарий работы пары устройство/брокер, когда вы имеете некоторый класс, который открывает соединение к каждому из двух устройств и управляет связью между ними. Брокер бесполезен, если доступно только одно устройство, поэтому семантика обработки транзакций при наличии брокера должна учитывать, что при выбрасывании исключения одним из двух этих устройств, когда делается попытка получения доступа к нему, должно освобождаться другое устройство. Это обеспечивает невозможность утечки памяти и других ресурсов.
Интервал:
Закладка: