Чтение онлайн

на главную - закладки

Жанры

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

Когсуэлл Джефф

Шрифт:

}

 }

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

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

buf_ = p;

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

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

appendData
просто использует временную переменную для хранения нового размера буфера. Это решает проблему, связанную с размером буфера, но обеспечит ли это на самом деле
базовую гарантию отсутствия утечки ресурсов? Обеспечит, но с трудом

сору
вызывает
operator=
для каждого элемента копируемой последовательности. В примере 9.4 каждый элемент имеет тип
char
, поэтому безопасность обеспечена, так как оператор присваивания одного символа другому не может выбросить никакого исключения. Но я сказал «обеспечит с трудом», потому что безопасность этого специального случая не должна создавать у вас впечатление о том, что причиной исключений никогда не может быть функция
copy
.

Предположим на секунду, что вместо «узкого» символьного буфера вам необходимо написать класс

Message
, который может содержать массив каких-то объектов. Вы могли бы представить его как шаблон класса, подобный представленному в примере 9.5.

Пример 9.5. Параметризованный класс сообщения

template<typename T>

class MessageGeneric {

public:

 MessageGeneric(int bufSize = DEFAULT_BUF_SIZE) :

bufSize_(bufSize), initBufSize_(bufSize), msgSize_(0), buf_(new T[bufSize]) {}

 ~MessageGeneric {

delete[] buf_;

 }

 void appendData(int len, const 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);

T* p = new T[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, T* data) {

if (maxLen < msgSize_) {

throw out of range("This data is too big for your buffer.");

}

copy(buf_, buf_+msgSize_, data);

return(msgSize_);

 }

private:

 MessageGeneric(const MessageGeneric& orig) {}

 MessageGeneric& operator=(const MessageGeneric& rhs) {}

 int bufSize_;

Поделиться:
Популярные книги

Камень. Книга восьмая

Минин Станислав
8. Камень
Фантастика:
фэнтези
боевая фантастика
7.00
рейтинг книги
Камень. Книга восьмая

Новый Рал 3

Северный Лис
3. Рал!
Фантастика:
попаданцы
5.88
рейтинг книги
Новый Рал 3

Бастард Императора. Том 4

Орлов Андрей Юрьевич
4. Бастард Императора
Фантастика:
попаданцы
аниме
фэнтези
фантастика: прочее
5.00
рейтинг книги
Бастард Императора. Том 4

Право на месть

Ледова Анна
3. Академия Ровельхейм
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Право на месть

Охота на попаданку. Бракованная жена

Герр Ольга
Любовные романы:
любовно-фантастические романы
5.60
рейтинг книги
Охота на попаданку. Бракованная жена

Законы Рода. Том 11

Андрей Мельник
11. Граф Берестьев
Фантастика:
юмористическое фэнтези
аниме
фэнтези
5.00
рейтинг книги
Законы Рода. Том 11

Светлая тьма. Советник

Шмаков Алексей Семенович
6. Светлая Тьма
Фантастика:
юмористическое фэнтези
городское фэнтези
аниме
сказочная фантастика
фэнтези
5.00
рейтинг книги
Светлая тьма. Советник

Бестужев. Служба Государевой Безопасности. Книга вторая

Измайлов Сергей
2. Граф Бестужев
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Бестужев. Служба Государевой Безопасности. Книга вторая

Идеальный мир для Лекаря 20

Сапфир Олег
20. Лекарь
Фантастика:
фэнтези
юмористическое фэнтези
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 20

Гардемарин Ее Величества. Инкарнация

Уленгов Юрий
1. Гардемарин ее величества
Фантастика:
городское фэнтези
попаданцы
альтернативная история
аниме
фантастика: прочее
5.00
рейтинг книги
Гардемарин Ее Величества. Инкарнация

Болотник

Панченко Андрей Алексеевич
1. Болотник
Фантастика:
попаданцы
альтернативная история
6.50
рейтинг книги
Болотник

Энфис 4

Кронос Александр
4. Эрра
Фантастика:
городское фэнтези
рпг
аниме
5.00
рейтинг книги
Энфис 4

Идеальный мир для Лекаря 14

Сапфир Олег
14. Лекарь
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 14

Идеальный мир для Лекаря 22

Сапфир Олег
22. Лекарь
Фантастика:
юмористическое фэнтези
аниме
фэнтези
5.00
рейтинг книги
Идеальный мир для Лекаря 22