|
Программирование >> Оптимизация возвращаемого значения
Указатели данного типа необходимо инициализировать с помощью списков инициализации в конструкторе BookEntry, потому что другого способа сделать это для указателей с атрибутом const нет. Очень часто возникает искушение инициализировать thelmage и theAudioClip следующим образом: / / Реализация, которая может привести к утечке ресурсов / / при возникновении исключения. BookEntry: : BookEntry (const string&name, const string& address = , const strings imageFileName= , const strings audioClipFileName = ) : theName(name),theAddress(address) , thelmage(imageFileName!= ? new lamge (imageFileName) : 0) , theAudioClip(audioClipFileName ! = ? new AudioClip(audioClipFileName) : 0) Ho это снова приводит к начальной проблеме: если исключение возникает во время инициализации theAudioClip, объект, на который указывает thelmage, не будет удален никогда. Более того, нельзя решить проблему, добавив в конструктор блоки try и catch, потому что try и catch являются операторами, а список инициализации элементов может включать только выражения. (В частности поэтому при инициализации указателей thelmage и theAudioClip пришлось использовать символы ? : вместо конструкции if-then-else.) Единственный способ выполнить код завершения перед тем, как обработка исключения выйдет за пределы конструктора, - перехватить эти исключения. Поэтому, если нельзя разместить блоки try и catch в списке инициализации, значит, придется разместить их где-то еще. Например, внутри внутренних функций, возвращающих указатели, значениями которых инициализируются объекты thelmage и theAudioClip: class BookEntry { public: ... Без изменений, private: ... Элементы данных без изменений. Image * initlmage (const strings imageFileName) ; AudioClip * initAudioClip (const strings AudioClipFileName); BookEntry : : BookEntry (const strings name , const strings address = , const strings imageFileName = , const strings audioClipFileName = ) : theName(name), theAddress(address) , thelmage(initlmage(ImageFileName)), theAudioClip(initAudioClip(audioClipFileName)) Объект thelmage инициализируется первым, следовательно, не стоит волноваться об утечке ресурсов, если инициализация окончится неудачно. Поэтому данная функция не обрабатывает исключения. Image * BookEntry: : initlmage (const strings ImageFileName) { if (ImageFileName != ) return new Image (ImageFileName) ; else return 0; Объект theAudioClip инициализируется вторым. Значит, необходимо принять меры по освобождению ресурсов, выделенных объекту thelmage, если во время инициализации / / theAudioClip возникнет исключение. / / Поэтому функция содержит блоки try и catch. AudioClip * BookEntry::initAudioClip(const strings AudioClipFileName) try { if (audioClipFileName ! = ) { return new AudioClip (audioClipFileName) ; else return 0 ; catch (...) { delete thelmage; throw; Этот фрагмент программы вполне работоспособен, и в нем даже решена главная проблема. Недостаток такого подхода состоит в том, что код, концептуально принадлежащий конструктору, оказался разбросанным по нескольким функциям, осложняя поддержку подобного программного обеспечения. Более грамотно будет принять рекомендацию правила 9 и считать объекты, на которые указывают thelmage и theAudioClip, ресурсами, управляемыми с помощью локальных объектов. Можно использовать то обстоятельство, что thelmage и theAudioClip являются указателями на динамически построенные объекты и при удалении указателей также должны быть удалены. Это именно те условия, для которых были сконструированы классы auto ptr (см. правило 9). Следовательно, можно заменить обычные указатели типов thelmage и theAudioClip на их эквиваленты типа auto ptr: class BookEntry { public: private: Вез изменений. const auto ptr<Image> thelmage; Теперь это const auto ptr<AudioClip>theAudioClip; объекты THnaauto ptr. Такой подход предотвращает утечку ресурсов в конструкторе BookEntry при возникновении исключений и позволяет инициализировать объекты thelmage и theAudioClip в списке инициализации: BookEntry: : BookEntry (const strings name, const strings address = , const strings imageFileName = , const strings audioClipFileName = ) : theName(name) , theAddress(address) , thelmage(imageFileName ! = ? new Image (imageFi leName) : 0) , theAudioClip(audioClipFileName ! = ? new AudioClip(audioClipFileName) : 0) Если исключение возникнет во время инициализации объекта theAudioClip, то объект thelmage уже будет полностью сконструирован, а значит, и автоматически удален наряду с объектами theName, theAddress и thePhones. Более того, поскольку теперь thelmage и theAudioClip являются объектами, они будут уничтожены в момент удаления включающего их объекта BookEntry. Следовательно, нет необходимости вручную удалять объекты, на которые они указывают. Это значительно упрощает деструктор BookEntry: BookEntry::-BookEntry() {} Ничего не надо делать! Таким образом, деструктор BookEntry можно вообще не создавать. Все вышеизложенное сводится к следующему: если заменить указатели на соответствующие объекты auto ptr, то снижается риск утечки ресурсов при возникновении исключений и исчезает необходимость освобождать ресурсы в деструкторах. Кроме того, члены-указатели с атрибутом const обрабатываются так же изящно, как и указатели без этого атрибута. Обработка исключения во время функционирования конструктора может оказаться не простым делом, но использование объектов auto ptr (и классов типа auto ptr) существенно облегчает задачу. Их применение позволяет создать простой для понимания и надежный код.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |