Определенно +1 на это, потому что я видел, как многие люди ошибаются. Это отличный вопрос.
Twokats
Пожалуйста, прочитайте также соответствующий пункт. Этот вопрос рассматривается здесь с другой стороны. Может быть полезно больше узнать о контейнерах auto_ptr и STL. stackoverflow.com/questions/8630552/…
moveсемантические и unique_ptrбыли разработаны, чтобы избежать проблем, связанных с auto_ptr. В C ++ 03 язык не был достаточно мощным, чтобы написать подобный класс, auto_ptrкоторый вел себя корректно и безопасно во всех сценариях, поскольку компилятор и язык не могли различать значения l и r, поэтому некоторые «хаки» использовались для получения желаемого поведения большую часть времени.
Стандарт 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.
Вы также должны рассмотреть контейнеры указателя наддува, если вам не нужно совместное владение.
me22
4
unique_ptrтакже запрещает копирование, поэтому некоторые операции STL не будут работать правильно, если они не могут использовать его семантику перемещения.
Майк Веллер
4
«Чтобы преодолеть это ограничение, вы должны использовать std::unique_ptr»: этот шаблон класса может существовать только из-за семантики перемещения (его спецификация требует ссылок на значения), поэтому он в основном требует C ++ 11. Однако (и связанный) стандарт C ++ 11 больше не говорит, что тип элемента STL должен быть «копируемым» и «присваиваемым»; быть способным к движению и назначаемым движением достаточно. Действительно, unique_ptrэкземпляры могут быть только конструируемыми и назначаемыми. Но так же, как и auto_ptrпримеры! Как следствие, в C ++ 11 вы можете делать auto_ptrто, что можете делать unique_ptr.
Марк ван Леувен
@MarcvanLeeuwen, если только вы resetи по releaseмере необходимости
чокнутый урод
2
@ratchetfreak: Хм, я не понимаю. Какой? «Если вы resetи release», я не вижу, как это относится к чему-либо в моем комментарии. Обратите внимание, что оба auto_ptrи unique_ptrимеют оба этих метода, и они делают одно и то же в обоих случаях.
Марк ван Леувен
66
В копировальной семантика из auto_ptrне совместимы с контейнерами.
В частности, копирование одного auto_ptrв другое не создает двух одинаковых объектов, поскольку один из них утратил право владения указателем.
Более конкретно, копирование auto_ptrприводит к тому, что одна из копий отпускает указатель. Что из этого остается в контейнере, не определено. Следовательно, вы можете случайно потерять доступ к указателям, если храните их auto_ptrsв контейнерах.
Потому что я думаю, что за прошедшие почти два года он, вероятно, занимался этой проблемой.
Щенок
27
@DeadMG: да, вы правы. Но это не было моей целью. Если кто-то когда-нибудь зайдет в эту ветку и захочет узнать auto_ptrи прочее, эти ссылки будут полезны, я уверен.
Лазер
Есть много дубликатов, которые более свежие.
Щенок
8
@DeadMG: Этот вопрос не был закрыт как дубликат и поэтому открыт для расширения. Лазер сказал то, что не было сказано раньше здесь. Я думаю, что он пришел случайно.
Себастьян Мах
Объяснения во второй ссылке, в которых анализируется проблема после звонка sort(), более понятны, чем все ответы здесь.
хаосинк
17
Контейнеры STL должны иметь возможность копировать элементы, которые вы храните в них, и должны рассчитывать на то, что оригинал и копия будут эквивалентны. Объекты с автоматическим указателем имеют совершенно другой договор, в результате чего копирование создает передачу права собственности. Это означает, что контейнеры auto_ptr будут демонстрировать странное поведение в зависимости от использования.
Подробное описание того, что может пойти не так, содержится в пункте 8 Effective STL (Скотт Мейерс), а также не очень подробное описание в пункте 13 Effective C ++ (Скотт Мейерс).
Контейнеры STL хранят копии содержащихся предметов. Когда auto_ptr копируется, он устанавливает старый ptr в ноль. Многие методы контейнера нарушаются этим поведением.
Но при использовании unique_ptr вы получаете почти то же самое, поскольку только один unique_ptr может иметь право собственности на объект?
Tracer
2
@Tracer, unique_ptrкак и любой надлежащий объект C ++ 11, может передавать право собственности на свой ресурс только при создании или назначении перемещения, гарантируя, что программист должен преднамеренно передать значение std::move(sourceObject)или временное значение, а не передавать значение l и неинтуитивно / непредсказуемо его мутировать с помощью копирование-задание ... которое, как здесь тщательно подчеркивалось, было основной проблемой auto_ptr.
underscore_d
4
Стандарт 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, который использует эти шаблоны классов и шаблоны функций, может не скомпилироваться в этом международном стандарте.
move
семантические иunique_ptr
были разработаны, чтобы избежать проблем, связанных сauto_ptr
. В C ++ 03 язык не был достаточно мощным, чтобы написать подобный класс,auto_ptr
который вел себя корректно и безопасно во всех сценариях, поскольку компилятор и язык не могли различать значения l и r, поэтому некоторые «хаки» использовались для получения желаемого поведения большую часть времени.Ответы:
Стандарт C ++ говорит, что элемент STL должен быть «копируемым» и «присваиваемым». Другими словами, элемент должен быть в состоянии быть назначенным или скопированным, и эти два элемента логически независимы.
std::auto_ptr
не выполняет это требование.Возьмите для примера этот код:
Чтобы преодолеть это ограничение, вы должны использовать
std::unique_ptr
,std::shared_ptr
илиstd::weak_ptr
умные указатели, или эквиваленты повышения, если у вас нет C ++ 11. Вот документация библиотеки поддержки для этих умных указателей.источник
unique_ptr
также запрещает копирование, поэтому некоторые операции STL не будут работать правильно, если они не могут использовать его семантику перемещения.std::unique_ptr
»: этот шаблон класса может существовать только из-за семантики перемещения (его спецификация требует ссылок на значения), поэтому он в основном требует C ++ 11. Однако (и связанный) стандарт C ++ 11 больше не говорит, что тип элемента STL должен быть «копируемым» и «присваиваемым»; быть способным к движению и назначаемым движением достаточно. Действительно,unique_ptr
экземпляры могут быть только конструируемыми и назначаемыми. Но так же, как иauto_ptr
примеры! Как следствие, в C ++ 11 вы можете делатьauto_ptr
то, что можете делатьunique_ptr
.reset
и поrelease
мере необходимостиreset
иrelease
», я не вижу, как это относится к чему-либо в моем комментарии. Обратите внимание, что обаauto_ptr
иunique_ptr
имеют оба этих метода, и они делают одно и то же в обоих случаях.В копировальной семантика из
auto_ptr
не совместимы с контейнерами.В частности, копирование одного
auto_ptr
в другое не создает двух одинаковых объектов, поскольку один из них утратил право владения указателем.Более конкретно, копирование
auto_ptr
приводит к тому, что одна из копий отпускает указатель. Что из этого остается в контейнере, не определено. Следовательно, вы можете случайно потерять доступ к указателям, если храните ихauto_ptrs
в контейнерах.источник
Две супер отличные статьи на эту тему:
источник
auto_ptr
и прочее, эти ссылки будут полезны, я уверен.sort()
, более понятны, чем все ответы здесь.Контейнеры STL должны иметь возможность копировать элементы, которые вы храните в них, и должны рассчитывать на то, что оригинал и копия будут эквивалентны. Объекты с автоматическим указателем имеют совершенно другой договор, в результате чего копирование создает передачу права собственности. Это означает, что контейнеры auto_ptr будут демонстрировать странное поведение в зависимости от использования.
Подробное описание того, что может пойти не так, содержится в пункте 8 Effective STL (Скотт Мейерс), а также не очень подробное описание в пункте 13 Effective C ++ (Скотт Мейерс).
источник
Контейнеры STL хранят копии содержащихся предметов. Когда auto_ptr копируется, он устанавливает старый ptr в ноль. Многие методы контейнера нарушаются этим поведением.
источник
unique_ptr
как и любой надлежащий объект C ++ 11, может передавать право собственности на свой ресурс только при создании или назначении перемещения, гарантируя, что программист должен преднамеренно передать значениеstd::move(sourceObject)
или временное значение, а не передавать значение l и неинтуитивно / непредсказуемо его мутировать с помощью копирование-задание ... которое, как здесь тщательно подчеркивалось, было основной проблемойauto_ptr
.Стандарт C ++ 03 (ISO-IEC 14882-2003) гласит в пункте 3 пункта 20.4.5:
Стандарт C ++ 11 (ISO-IEC 14882-2011) гласит в добавлении D.10.1 пункт 3:
Стандарт C ++ 14 (ISO-IEC 14882-2014) гласит в приложении C.4.2 Приложение D: функции совместимости:
источник