Эффективное использование C++. 55 верных способов улучшить структуру и код ваших программ | страница 58



>pInv(createStatement()); // вызвать фабричную функцию

>... // использовать pInv как раньше

>} // автоматически удалить pInv

>// деструктором shared_ptr


Этот код выглядит почти так же, как и использующий auto_ptr, но shared_ptr при копировании ведет себя гораздо более естественно:


>void f()

>{

>...

>std::tr1::shared_ptr // pInv1 указывает на объект,

>pInv1(createStatement()); // возвращенный createInvestment

>std::tr1::shared_ptr // теперь оба объекта pInv1 и pInv2

>pInv2(pInv1); // указывают на объект

>pInv1 = pInv2; // ничего не изменилось

>...

>} // pInv1 и pInv2 уничтожены, а объект,

>// на который они указывали,

>// автоматически удален


Поскольку копирование объектов tr1::shared_ptr работает «как ожидается», то они могут быть использованы в качестве элементов STL-контейнеров, а также в других случаях, когда непривычное поведение auto_ptr нежелательно.

Однако не заблуждайтесь. Это правило посвящено не auto_ptr и tr1::shared_ptr, или любым другим типам интеллектуальных указателей. Здесь мы говорим о важности использования объектов для управления ресурсами. auto_ptr и tr1::shared_ptr – всего лишь примеры объектов, которые делают это. (Более подробно о tr1::shared_ptr читайте в правилах 14, 18 и 54.)

И auto_ptr, и tr1::shared_ptr в своих деструкторах используют оператор delete, а не delete[]. (Разница между ними описана в правиле 16.) Это значит, что нельзя применять auto_ptr и tr1::shared_ptr к динамически выделенным массивам, хотя, как это ни прискорбно, следующий код скомпилируется:


>std::auto_ptr // плохая идея! Будет

>aps(new std::string[10]); // использована не та форма

>// оператора delete

>std::tr1::shared_ptr spi(new int[1024]); // та же проблема


Вас может удивить, что не предусмотрено ничего подобного auto_ptr или tr1::shared_ptr для работы с динамически выделенными массивами – ни в C++, ни даже в TR1. Это объясняется тем, что такие массивы почти всегда можно заменить векторами или строками (vector и string). Если вы все-таки считаете, что было бы неплохо иметь auto_ptr и tr1::shared_ptr для массивов, обратите внимание на библиотеку Boost (см. правило 55). Там вы найдете классы boost::scoped_array и boost::shared_array, которые предоставляют нужное вам поведение.

Излагаемые здесь правила по использованию объектов для управления ресурсами предполагают, что если вы освобождаете ресурсы вручную (например, применяя delete помимо того, который содержится в деструкторе управляющего ресурсами класса), то поступаете неправильно. Готовые классы для управления ресурсами – вроде auto_ptr и tr1::shared_ptr – часто облегчают выполнение советов из настоящего правила, но иногда приходится иметь дело с ресурсами, для которых поведение этих классов неадекватно. В таких случаях вам придется разработать собственные классы управления ресурсами. Это не так уж трудно сделать, но нужно принять во внимание некоторые соображения (см. правила 14 и 15).