Д. Стефенс - C++. Сборник рецептов

Тут можно читать онлайн Д. Стефенс - C++. Сборник рецептов - бесплатно полную версию книги (целиком) без сокращений. Жанр: comp-programming, издательство КУДИЦ-ПРЕСС, год 2007. Здесь Вы можете читать полную версию (весь текст) онлайн без регистрации и SMS на сайте лучшей интернет библиотеки ЛибКинг или прочесть краткое содержание (суть), предисловие и аннотацию. Так же сможете купить и скачать торрент в электронном формате fb2, найти и слушать аудиокнигу на русском языке или узнать сколько частей в серии и всего страниц в публикации. Читателям доступно смотреть обложку, картинки, описание и отзывы (комментарии) о произведении.
  • Название:
    C++. Сборник рецептов
  • Автор:
  • Жанр:
  • Издательство:
    КУДИЦ-ПРЕСС
  • Год:
    2007
  • Город:
    Москва
  • ISBN:
    5-91136-030-6
  • Рейтинг:
    3.9/5. Голосов: 101
  • Избранное:
    Добавить в избранное
  • Отзывы:
  • Ваша оценка:
    • 80
    • 1
    • 2
    • 3
    • 4
    • 5

Д. Стефенс - C++. Сборник рецептов краткое содержание

C++. Сборник рецептов - описание и краткое содержание, автор Д. Стефенс, читайте бесплатно онлайн на сайте электронной библиотеки LibKing.Ru

Данная книга написана экспертами по C++ и содержит готовые рецепты решения каждодневных задач для программистов на С++. Один из авторов является создателем библиотеки Boost Iostreams и нескольких других библиотек C++ с открытым исходным кодом. В книге затрагивается множество тем, вот лишь некоторые из них: работа с датой и временем; потоковый ввод/вывод; обработка исключений; работа с классами и объектами; сборка приложений; синтаксический анализ XML-документов; программирование математических задач. Читатель сможет использовать готовые решения, а сэкономленное время и усилия направить на решение конкретных задач.

C++. Сборник рецептов - читать онлайн бесплатно полную версию (весь текст целиком)

C++. Сборник рецептов - читать книгу онлайн бесплатно, автор Д. Стефенс
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

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);

} catch (...) {

delete dev1_; // Это сработает в любом случае

throw;

}

}

Итак, вышесказанное можно подытожить следующим образом: если вам необходимо использовать члены-указатели, инициализируйте их значением NULLв списке инициализации и затем выделяйте в конструкторе память для соответствующих объектов, используя блок try/catch. Вы можете освободить любую память в catch-обработчике. Однако, если допускается работа с автоматическими членами, сконструируйте их в списке инициализации и используйте специальный синтаксис блока try/catchдля обработки любых исключений.

Смотри также

Рецепт 9.2.

9.4. Создание безопасных при исключениях функций-членов

Проблема

Создается функция-член и необходимо обеспечить базовые и строгие гарантии ее безопасности при исключениях, а именно отсутствие утечки ресурсов и то, что объект не будет иметь недопустимое состояние в том случае, если выбрасывается исключение.

Решение

Необходимо выяснить, какие операции могут выбрасывать исключения, и следует выполнить их первыми, обычно заключая в блок try/catch. После того как будет выполнен программный код, который может выбрасывать исключение, вы можете изменять состояние объектов. В примере 9.4 показан один из способов обеспечения безопасности функции-члена при исключениях.

Пример 9.4. Безопасная при исключениях функция-член

class Message {

public:

Message(int bufSize = DEFAULT_BUF_SIZE) :

bufSize_(bufSize), initBufSize_(bufSize), msgSize_(0), buf_(NULL) {

buf_ = new char[bufSize];

}

~Message() {

delete[] buf_;

}

// Добавить в конец символьные данные

void appendData(int len, const char* data) {

if (msgSize_+len > MAX_SIZE) {

throw out_of_range("Data size exceeds maximum size.");

}

if (msgSize_+len > bufSize_) {

int newBufSize = bufSize_;

while ((newBufSize *= 2) < msgSize_+len);

char* p = new char[newBufSize]; // Выделить память

// для нового буфера

copy(buf_, buf_+msgSize_, p); // Скопировать старые данные

copy(data, data+len, p+msgSize_); // Скопировать новые данные

msgSize_ += len;

bufSize_ = newBufSize;

delete[] buf_; // Освободись старый буфер и установить указатель на

buf_ = p; // новый буфер

} else {

copy(data, data+len, buf_+msgSize_);

msgSize_ += len;

}

}

// Скопировать данные в буфер вызывающей программы

int getData(int maxLen, char* data) {

if (maxLen < msgSize_) {

throw out_of_range("This data is too big for your buffer.");

}

copy(buf_, buf_+msgSize_, data);

return(msgSize_);

}

private:

Message(const Message& orig) {} // Мы рассмотрим эти операторы

Message& operator=(const Message& rhs) {} // в рецепте 9.5

int bufSize_;

int initBufSize_;

int msgSize_;

char* buf_;

};

Обсуждение

Представленный в примере 9.4 класс Messageявляется классом, содержащим символьные данные; вы могли бы использовать его в качестве оболочки текстовых или бинарных данных, которые передаются из одной системы в другую. Здесь нас интересует функция-член appendData, которая добавляет данные, переданные вызывающей программой, в конец данных, уже находящихся в буфере, причем увеличивая при необходимости размер буфера. Здесь обеспечивается строгая гарантия безопасности этой функции-члена при исключениях, хотя на первый взгляд может быть не совсем понятно, чем это достигается.

Рассмотрим следующий фрагмент appendData.

if (msgSize_+len > bufSize_) {

int newBufSize = bufSize_;

while ((newBufSize *= 2) < msgSize_+len);

char* p = new char[newBufSize];

Этот блок программного кода обеспечивает увеличение размера буфера. Я его увеличиваю путем удвоения его размера до тех пор, пока он не станет достаточно большим. Этот фрагмент программного кода безопасен, потому что исключение может быть выброшено здесь только при выполнении оператора new, и я не обновляю состояние объекта и не выделяю память ни под какие другие ресурсы до завершения его выполнения. Этот оператор выбросит исключение bad_alloc, если операционная система не сможет выделить участок памяти необходимого размера.

После успешного распределения памяти я могу начать обновление состояния объекта, копируя данные и обновляя значения переменных-членов.

copy(buf_, buf_+msgSize_, p);

copy(data, data+len, p+msgSize_);

msgSize_ += len;

bufSize_ = newBufSize;

delete[] buf_;

Читать дальше
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать


Д. Стефенс читать все книги автора по порядку

Д. Стефенс - все книги автора в одном месте читать по порядку полные версии на сайте онлайн библиотеки LibKing.




C++. Сборник рецептов отзывы


Отзывы читателей о книге C++. Сборник рецептов, автор: Д. Стефенс. Читайте комментарии и мнения людей о произведении.


Понравилась книга? Поделитесь впечатлениями - оставьте Ваш отзыв или расскажите друзьям

Напишите свой комментарий
x