Почему unique_ptr можно использовать с контейнерами std, например с векторами <>?

Я понимаю, что auto_ptr нельзя использовать с векторами, поскольку auto_ptr не соответствует требованию быть копируемым конструктором. Поскольку копируемый auto_ptr изменяется, копирование не приводит к двум точным копиям, нарушая тем самым конструкцию копии.

Unique_ptr также, кажется, делает то же самое; он изменяет копируемый объект - для элемента указателя копируемого объекта устанавливается значение nullptr. Тогда как можно использовать uinque_ptr с векторами, а не с auto_ptrs?

Правильно ли мое понимание или я что-то здесь упускаю?

auto_ptr <int> autoPtr(new int);
vector < auto_ptr <int> > autoVec;
autoVec.push_back(autoPtr);         //compiler error..why?

unique_ptr <int> uniquePtr(new int);
vector < unique_ptr <int> > uniqueVec;
uniqueVec.push_back(std::move(uniquePtr));  //okay..why?

2 ответа

Проблема с auto_ptr было то, что операция, которая не должна была изменить объект, изменила его. Конструктор копирования изменил источник.

unique_ptr не имеет конструктора копирования. У него есть конструктор перемещения. Конструктор перемещения также изменяет исходный код, но это ожидаемо, и универсальный код может различать ситуации, в которых используется конструктор копирования, и ситуации, в которых используется конструктор перемещения.

vector (и другие контейнеры) не просто волшебным образом работали с unique_ptr однажды это было написано. Их нужно было обновить, чтобы они могли работать только с типами перемещения. Это было сделано в C++11. Эту модификацию можно было сделать, потому что перемещение и копирование - это разные операции. Не было возможности сделать то же самое для auto_ptr потому что у этого класса был странный конструктор копирования.

Ошибка компиляции из-за попытки изменить auto_ptr const& формальный аргумент (копируя его) в push_back реализация.

Вместо

autoVec.push_back(autoPtr);

ты можешь сделать

autoVec.emplace_back( autoPtr.release() );

или более напрямую (не используя autoPtr переменная)

autoVec.emplace_back( new int(42) );

Однако, хотя это работает в техническом смысле (отказ от ответственности: код даже не просматривается никаким компилятором), у вас все еще есть проблема auto_ptr элементы обнулялись в результате попытки копирования. Так что это все очень и очень небезопасно. Дополнительно, auto_ptr устарел в C++11; Я не знаю, был ли он вообще удален сейчас, но это не исключено.

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