std :: auto_ptr в std :: unique_ptr

185

С появлением нового стандарта (и частей, уже доступных в некоторых компиляторах), новый тип std::unique_ptrдолжен заменить его std::auto_ptr.

Их использование в точности совпадает (поэтому я могу выполнить глобальный поиск / замену в моем коде (не то, чтобы я это делал, но если бы я это сделал)) или я должен знать о некоторых различиях, которые не очевидны при чтении документации?

Кроме того, если это прямая замена, зачем давать ему новое имя, а не просто улучшать std::auto_ptr?

Мартин Йорк
источник

Ответы:

219

Вы не можете выполнить глобальный поиск / замену, потому что вы можете скопировать auto_ptr(с известными последствиями), но a unique_ptrможно только переместить. Все, что выглядит

std::auto_ptr<int> p(new int);
std::auto_ptr<int> p2 = p; 

должен будет стать как минимум таким

std::unique_ptr<int> p(new int);
std::unique_ptr<int> p2 = std::move(p);

Что касается других отличий, unique_ptrможет правильно обрабатывать массивы (он будет вызывать delete[], пока auto_ptrбудет пытаться вызвать) delete.

Cubbi
источник
101
с другой стороны, выполнение этого поиска / замены приведет только к ошибкам компиляции, насколько я могу видеть, он не будет молча нарушать код. Так что это безопасно, если вы вручную исправите ошибки компиляции
jalf
7
@jalf: Действительно, я не могу вспомнить контрпример, который был бы хорошо определен с auto_ptrs и UB с unique_ptrs.
Cubbi
1
кажется, что unique_ptr является улучшением auto_ptr: поддержка массивов и устранение неоднозначности
Baiyan Huang
92

std::auto_ptrи std::unique_ptrнесовместимы в некоторых случаях и падение замены в других. Таким образом, поиск / замена не достаточно хорош. Однако после поиска / замены, работающего с ошибками компиляции, следует исправить все, кроме странных угловых случаев. Большинство ошибок компиляции потребует добавления std::move.

  • Переменная области действия функции:
    совместимость на 100%, если вы не передаете ее по значению другой функции.
  • Тип возврата:
    не на 100% совместимый, но на 99% совместимый не кажется неправильным.
  • Параметр функции по значению:
    100% совместимость с одним предупреждением, unique_ptrs должны быть переданы через std::moveвызов. Это просто, так как компилятор будет жаловаться, если вы не поняли это правильно.
  • Функциональный параметр по ссылке:
    100% совместимость.
  • Переменная члена класса:
    эта хитрая. std::auto_ptrСемантика копирования зла. Если класс запрещает копирование, тогда std::unique_ptrзамена заменяется. Однако, если вы попытались дать разумную семантику копирования классу, вам придется изменить std::auto_ptrкод обработки. Это просто, так как компилятор будет жаловаться, если вы не понимаете это правильно. Если вы разрешили копировать класс с std::auto_ptrучастником без какого-либо специального кода, то позор вам и удачи.

Таким образом, std::unique_ptrэто непрерывный std::auto_ptr. Он запрещает во время компиляции поведения, которые часто были ошибками при использовании std::auto_ptr. Так что, если вы используете std::auto_ptrс должной осторожностью, переключение на std::unique_ptrдолжно быть простым. Если вы полагались на std::auto_ptrстранное поведение, то вам все равно нужно реорганизовать свой код.

deft_code
источник
8
+1 за "вам все равно нужно реорганизовать свой код". auto_ptrs хороши только для того, что 20.4.5 / 3 говорит, что они хороши для.
Cubbi
8
Позвольте мне добавить к этому, что вы обязательно должны заменить auto_ptr на unique_ptr в своем коде и исправить ошибки компиляции. Вы будете удивлены, сколько ошибок это обнаружит.
Бартош Милевски
36

AFAIK, unique_ptrэто не прямая замена. Основным недостатком, который он исправляет, является неявная передача права собственности.

std::auto_ptr<int> a(new int(10)), b;
b = a; //implicitly transfers ownership

std::unique_ptr<int> a(new int(10)), b;
b = std::move(a); //ownership must be transferred explicitly

С другой стороны, unique_ptrпоявятся совершенно новые возможности: их можно хранить в контейнерах.

Дядя Бен
источник
8
Скотт Мейерс также упомянул в своем «Эффективном C ++» (3-е издание), пункт 13 (стр. 64), что контейнеры STL требуют, чтобы их содержимое демонстрировало «нормальное» копирование, поэтому контейнеры auto_ptrне допускаются.
Цян Сюй
31

У Херба Саттера есть хорошее объяснение на GotW # 89 :

Что за дело с auto_ptr? auto_ptr наиболее мягко охарактеризован как доблестная попытка создать unique_ptr до того, как в C ++ появилась семантика перемещения. auto_ptr устарел и не должен использоваться в новом коде.

Если у вас есть auto_ptr в существующей кодовой базе, когда у вас появится возможность, попробуйте выполнить глобальный поиск и замену auto_ptr на unique_ptr; Подавляющее большинство применений будет работать одинаково, и это может раскрыть (как ошибка во время компиляции) или исправить (молча) ошибку или два, о которых вы не знали, что у вас есть.

Другими словами, хотя глобальный поиск и замена может временно «сломать» ваш код, вы все равно должны это сделать: это может занять некоторое время, чтобы исправить ошибки компиляции, но избавит вас от многих проблем в долгосрочной перспективе.

ValarDohaeris
источник
Отличная ссылка. Большое спасибо!
Фотнелтон