Почему неправильно использовать std::auto_ptr<> со стандартными контейнерами?

Почему это неправильно использовать std::auto_ptr<> со стандартными контейнерами?

6 ответов

Решение

Стандарт C++ говорит, что элемент STL должен быть "копируемым" и "присваиваемым". Другими словами, элемент должен иметь возможность быть назначенным или скопированным, и эти два элемента логически независимы. std::auto_ptr не выполняет это требование.

Возьмите для примера этот код:

class X
{
};

std::vector<std::auto_ptr<X> > vecX;
vecX.push_back(new X);

std::auto_ptr<X> pX = vecX[0];  // vecX[0] is assigned NULL.

Чтобы преодолеть это ограничение, вы должны использовать std::unique_ptr, std::shared_ptr или же std::weak_ptr умные указатели или эквиваленты повышения, если у вас нет C++11. Вот документация библиотеки поддержки для этих умных указателей.

Копия семантики auto_ptr не совместимы с контейнерами.

В частности, копирование одного auto_ptr другой не создает два равных объекта, поскольку один из них утратил право владения указателем.

Более конкретно, копирование auto_ptr заставляет одну из копий отпустить указатель. Что из этого остается в контейнере, не определено. Поэтому вы можете случайно потерять доступ к указателям, если храните auto_ptrs в контейнерах.

Две супер отличные статьи на эту тему:

Контейнеры STL должны иметь возможность копировать элементы, которые вы храните в них, и должны рассчитывать на то, что оригинал и копия будут эквивалентны. Объекты с автоматическим указателем имеют совершенно другой договор, в результате чего копирование создает передачу права собственности. Это означает, что контейнеры auto_ptr будут демонстрировать странное поведение в зависимости от использования.

Подробное описание того, что может пойти не так, содержится в пункте 8 Effective STL (Скотт Мейерс), а также не очень подробное описание в пункте 13 Effective C++ (Скотт Мейерс).

Контейнеры STL хранят копии содержащихся предметов. Когда auto_ptr копируется, он устанавливает старый ptr в ноль. Многие контейнерные методы нарушаются этим поведением.

Стандарт C++03 (ISO-IEC 14882-2003) гласит в пункте 3 пункта 20.4.5:

[...] [ Примечание: [...] auto_ptr не соответствует требованиям CopyConstructible и Assignable для элементов контейнера стандартной библиотеки и, следовательно, создание экземпляра контейнера стандартной библиотеки с auto_ptr приводит к неопределенному поведению. - конец примечания ]

Стандарт C++11 (ISO-IEC 14882-2011) гласит в добавлении D.10.1 пункт 3:

[...] Примечание: [...] Экземпляры auto_ptr соответствуют требованиям MoveConstructible и MoveAssignable, но не соответствуют требованиям CopyConstructible и CopyAssignable. - конец примечания]

Стандарт C++14 (ISO-IEC 14882-2014) гласит в приложении C.4.2 Приложение D: функции совместимости:

Изменение: шаблоны классов auto_ptr, unary_function и binary_function, шаблоны функций random_shuffle и шаблоны функций (и их возвращаемые типы) ptr_fun, mem_fun, mem_fun_ref, bind1st и bind2nd не определены.
Обоснование: заменено новыми функциями.
Эффект на исходную функцию: допустимый код C ++ 2014, который использует эти шаблоны классов и шаблоны функций, может не скомпилироваться в этом международном стандарте.

Другие вопросы по тегам