Почему неправильно использовать 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, который использует эти шаблоны классов и шаблоны функций, может не скомпилироваться в этом международном стандарте.