Таким образом, unique_ptr может использоваться безопасно в stl наборах?

Я перепутан с unique_ptr и философией перемещения rvalue.

Скажем, у нас есть два набора:

std::vector<std::auto_ptr<int>> autoCollection;
std::vector<std::unique_ptr<int>> uniqueCollection;

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

std::sort(autoCollection.begin(), autoCollection.end());

Я получаю это. И компилятор справедливо запрещает этот случай.

Но затем я делаю это:

std::sort(uniqueCollection.begin(), uniqueCollection.end());

И это компилирует. И я не понимаю почему. Я не думал, что unique_ptrs мог быть скопирован. Это означает, что значение центра не может быть принято, таким образом, вид менее эффективен? Или этот центр является на самом деле перемещением, которое на самом деле так же опасно как набор auto_ptrs и должно быть запрещено компилятором?

Я думаю, что пропускаю некоторую решающую информацию, таким образом, я нетерпеливо жду кого-то для предоставления меня ага! момент.

43
задан DanDan 20 May 2010 в 18:28
поделиться

2 ответа

Я думаю, что это больше вопрос философии, чем техники :)

Основной вопрос в том, в чем разница между Move и Copy. Я не буду переходить на технический/стандартизированный язык, давайте сделаем это просто:

  • Copy: создать другой идентичный объект (или, по крайней мере, тот, который ДОЛЖЕН сравниться с аналогичным)
  • Move: взять объект и поместить его в другое место

Как вы сказали, можно реализовать Move в терминах Copy: создать копию в новом месте и отбросить оригинал. Однако здесь есть две проблемы. Первая - производительность, вторая - объекты, используемые для RAII: кто из двух должен иметь право собственности?

Правильный конструктор Move решает эти две проблемы:

  • Ясно, какой объект имеет право собственности: новый, поскольку оригинал будет отброшен
  • Таким образом, нет необходимости копировать ресурсы, на которые указывают, что позволяет повысить эффективность

Очень хорошей иллюстрацией этого являются auto_ptr и unique_ptr.

С auto_ptr у вас испорчена семантика Copy: оригинал и копия не равны. Вы можете использовать его для семантики Move, но есть риск, что вы потеряете объект, на который указываете.

С другой стороны, unique_ptr именно таков: он гарантирует уникальность владельца ресурса, что позволяет избежать копирования и неизбежной проблемы удаления, которая за этим последует. Причем отсутствие копирования гарантируется и во время компиляции. Поэтому он подходит для контейнеров до тех пор, пока вы не пытаетесь инициализировать копию.

typedef std::unique_ptr<int> unique_t;
typedef std::vector< unique_t > vector_t;

vector_t vec1;                           // fine
vector_t vec2(5, unique_t(new Foo));     // Error (Copy)
vector_t vec3(vec1.begin(), vec1.end()); // Error (Copy)
vector_t vec3(make_move_iterator(vec1.begin()), make_move_iterator(vec1.end()));
    // Courtesy of sehe

std::sort(vec1.begin(), vec1.end()); // fine, because using Move Assignment Operator

std::copy(vec1.begin(), vec1.end(), std::back_inserter(vec2)); // Error (copy)

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

К сожалению, Visual Studio может быть довольно вялой в применении стандарта, а также имеет ряд расширений, которые необходимо отключить для обеспечения переносимости кода... не используйте ее для проверки стандарта :)

.
52
ответ дан 26 November 2019 в 22:57
поделиться

Перемещение unique_ptrов осуществляется с помощью их конструктора перемещения. unique_ptr является Movable, но не CopyConstructable.

Есть отличная статья о ссылках rvalue здесь. Если вы еще не читали о них или запутались, посмотрите!

12
ответ дан 26 November 2019 в 22:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: