Д. Стефенс - 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++. Сборник рецептов - читать книгу онлайн бесплатно, автор Д. Стефенс
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

Пример 9.6. Безопасные при исключениях оператор присваивания и конструктор копирования

#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_("") {

buf_ = new char[bufSize]; // Примечание: теперь это делается в теле

// конструктора

}

~Message() {

delete[] buf_;

}

// Безопасный при исключениях конструктор копирования

Message(const Message& orig) :

bufSize_(orig.bufSize_), initBufSize_(orig.initBufSize_),

msgSize_(orig.msgSize_), key_(orig.key_) {

// Эта функция может выбросить исключение

buf_ = new char[orig.bufSize_]; // ...здесь может произойти то же

// самое

copy(orig.buf_, orig.buf_+msgSize_, buf_); // Здесь нет

}

// Безопасный при исключениях оператор присваивания использующий

// конструктор копирования

Message& operator=(const Message& rhs) {

Message tmp(rhs); // Копировать сообщение во временную переменную,

// используя конструктор копирования

swapInternals(tmp); // Обменять значения переменных-членов и членов

// временного объекта

return(*this); // После выхода переменная tmp уничтожается вместе

// с первоначальными данными

}

const char* data() {

return(buf_);

}

private:

void swapInternals(Messages msg) {

// Поскольку key_ не является встроенным типом данных, он может

// выбрасывать исключение, поэтому сначала выполняем действия с ним

swap(key_, msg.key_);

// Если предыдущий оператор не выбрасывает исключение, то выполняем

// действия со всеми переменными-членами, которые являются встроенными

// типами

swap(bufSize_, msg.bufSize_);

swap(initBufSize_, msg.initBufSize_);

swap(msgSize_, msg.msgSize_);

swap(buf_, msg.buf_);

}

int bufSize_;

int initBufSize_;

int msgSize_;

char* buf;

string key_;

}

Обсуждение

Вся работа здесь делается конструктором копирования и закрытой функцией-членом swapInternals. Конструктор копирования инициализирует в списке инициализации элементарные члены и один из неэлементарных членов. Затем он распределяет память для нового буфера и копирует туда данные. Довольно просто, но почему используется такая последовательность действий? Вы могли бы возразить, что всю инициализацию можно сделать в списке инициализации, но такой подход может сопровождаться тонкими ошибками.

Например, вы могли бы следующим образом выделить память под буфер в списке инициализации.

Message(const Message& orig) :

bufSize_(orig bufSize_), initBufSize_(orig initBufSize_),

msgSize_(orig.msgSize_), key_(orig.key_),

buf_(new char[orig.bufSize_]){

copy(orig.buf_, orig.buf_+msgSize_, buf_);

}

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

int bufSize_;

int initBufSize_;

int msgSize_;

char* buf_;

string key_;

В результате buf_будет инициализироваться перед key_. Если при инициализации key_будет выброшено исключение, buf_не будет уничтожен, и у вас образуется участок недоступной памяти. От этого можно защититься путем использования в конструкторе блока try/catch(см. рецепт 9.2), но проще разместить оператор инициализации buf_в теле конструктора, что гарантирует его выполнение после операторов списка инициализации.

Выполнение функции copyне приведет к выбрасыванию исключения, так как она копирует элементарные значения. Но именно это место является тонким с точки зрения безопасности исключений: эта функция может выбросить исключение, если копируются объекты (например, если речь идет о контейнере, который параметризован типом своих элементов, T); в этом случае вам придется перехватывать исключение и освобождать связанную с ним память.

Вы можете поступить по-другому и копировать объект при помощи оператора присваивания, operator=. Поскольку этот оператор и конструктор копирования выполняют аналогичные действия (например, приравнивают члены моего класса к членам аргумента), воспользуйтесь тем, что вы уже сделали, и вы облегчите себе жизнь. Единственная особенность заключается в том, что вы можете сделать более привлекательным ваш программный код, используя закрытую функцию-член для обмена значений между данными-членами и временным объектом. Мне бы хотелось быть изобретателем этого приема, но я обязан отдать должное Гербу Саттеру (Herb Sutter) и Стефану Дьюхарсту (Stephen Dewhurst), в работе которых я впервые познакомился с этим подходом.

Возможно, вам все здесь ясно с первого взгляда, но я дам пояснения на тот случай, если это не так. Рассмотрим первую строку, в которой создается временный объект tmpс помощью конструктора копирования.

Message tmp(rhs);

В данном случае мы просто создали двойника объекта-аргумента. Естественно, теперь tmpэквивалентен rhs. После этого мы обмениваем значения его членов со значениями членов объекта *this.

swapInternals(tmp);

Вскоре я вернусь к функции swapInternals. В данный момент нам важно только то, что члены *thisимеют значения, которые имели члены tmpсекунду назад. Однако объект tmpпредставлял собой копию объекта rhs, поэтому теперь *thisэквивалентен rhs. Но подождите: у нас по-прежнему имеется этот временный объект. Нет проблем, когда вы возвратите *this, tmp будет автоматически уничтожен вместе со старыми значениями переменных-членов при выходе за диапазон его видимости.

return(*this);

Все так. Но обеспечивает ли это безопасность при исключениях? Безопасно конструирование объекта tmp, поскольку наш конструктор является безопасным при исключениях. Большая часть работы выполняется функцией swapInternals, поэтому рассмотрим, что в ней делается, и безопасны ли эти действия при исключениях.

Функция swapInternalsвыполняет обмен значениями между каждым данным-членом текущего объекта и переданного ей объекта. Это делается с помощью функции swap, которая принимает два аргумента a и b , создает временную копию a , присваивает аргумент b аргументу а и затем присваивает временную копию аргументу b . В этом случае такие действия являются безопасными и нейтральными по отношению к исключениям, так как источником исключений здесь могут быть только объекты, над которыми выполняются операции. Здесь не используется динамическая память и поэтому обеспечивается базовая гарантия отсутствия утечки ресурсов.

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

Интервал:

Закладка:

Сделать


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

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




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


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


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

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