std::auto_ptrInvestment pInv2(pInv1); // pInv2 теперь указывает на объект,
// а pInv1 равен null
pInv1 = pInv2; // теперь pInv1 указывает на объект,
// а pInv2 равно null
Это странное поведение при копировании плюс лежащее в его основе требование о том, что ни на какой ресурс, управляемый auto_ptr, не должен указывать более чем один auto_ptr, означает, что auto_ptr – не всегда является наилучшим способом управления динамически выделяемыми ресурсами. Например, STL-контейнеры требуют, чтобы их содержимое при копировании вело себя «нормально», поэтому помещать в них объекты auto_ptr нельзя.
Альтернатива auto_ptr – это
Класс tr1::shared_prt из библиотеки TR1 (см. правило 54) – это типичный пример RCSP, поэтому вы можете написать:
void f
{
...
std::tr1::shared_ptrInvestment
pInv(createStatement); // вызвать фабричную функцию
... // использовать pInv как раньше
} // автоматически удалить pInv
// деструктором shared_ptr
Этот код выглядит почти так же, как и использующий auto_ptr, но shared_ptr при копировании ведет себя гораздо более естественно:
void f
{
...
std::tr1::shared_ptrInvestment // pInv1 указывает на объект,
pInv1(createStatement); // возвращенный createInvestment
std::tr1::shared_ptrInvestment // теперь оба объекта 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_ptrstd::string // плохая идея! Будет
aps(new std::string[10]); // использована не та форма
// оператора delete
std::tr1::shared_ptrint 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, которые предоставляют нужное вам поведение.