Какие плюсы и минусы у устаревшего умного указателя `auto_ptr` в C++?

«Какие плюсы и минусы у устаревшего умного указателя `auto_ptr` в C++?» — вопрос из категории Управление памятью, который задают на 25% собеседований C/C++ Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

auto_ptr, представленный в C++98, был первой попыткой стандартной библиотеки реализовать умный указатель с семантикой единоличного владения (RAII). В C++11 он был признан устаревшим (deprecated) и полностью удалён в C++17, заменённый на std::unique_ptr.

Исторические плюсы auto_ptr (в контексте C++98):

  • Введение принципа RAII для сырых указателей. Автоматически освобождал память при выходе из области видимости, что было большим шагом вперёд по сравнению с ручным new/delete.
  • Нулевые накладные расходы. По производительности и размеру был эквивалентен сырому указателю, не требовал дополнительной памяти для счётчиков ссылок (в отличие от std::shared_ptr).

Критические минусы auto_ptr, приведшие к его замене:

  1. Неявный и опасный перенос владения при копировании. Это была его самая большая проблема. При копировании auto_ptr исходный объект обнулялся (становился nullptr). Это нарушало интуитивные ожидания от семантики копирования и приводило к тонким ошибкам.

    std::auto_ptr<int> p1(new int(42));
    std::auto_ptr<int> p2 = p1; // p1 теперь равен nullptr!
    // *p1; // Неопределённое поведение: разыменование nullptr.
  2. Несовместимость с контейнерами STL. Контейнеры (например, std::vector) требуют, чтобы типы элементов имели "нормальную" семантику копирования. Из-за своего "перемещающего" копирования auto_ptr не мог безопасно использоваться в STL-контейнерах, что сильно ограничивало его применимость.

  3. Отсутствие поддержки массивов (new[]). auto_ptr использовал delete, а не delete[], поэтому его нельзя было использовать для управления динамическими массивами.

  4. Отсутствие возможности пользовательского удалителя (deleter). Нельзя было задать собственную функцию для освобождения ресурса (например, для fclose или специального аллокатора).

Вывод: auto_ptr был важным, но неудачным экспериментом. В современном C++ всегда следует использовать std::unique_ptr, который лишён этих недостатков: имеет явную семантику перемещения (а не копирования), работает с контейнерами, поддерживает массивы (unique_ptr<T[]>), позволяет задавать пользовательский делитер и предоставляет более богатый и безопасный интерфейс.