Я думаю, что это больше вопрос философии, чем техники :) 1001 *
Основной вопрос заключается в том, в чем разница между перемещением и копированием. Я не буду переходить на технический / стандартный язык, давайте сделаем это просто:
- Копировать: создать другой идентичный объект (или, по крайней мере, тот, который ДОЛЖЕН сравниваться равным)
- Перемещение: возьмите объект и поместите его в другое место
Как вы сказали, можно реализовать Move в терминах Copy: создать копию в новом месте и удалить оригинал. Однако здесь есть два вопроса. Один из них связан с производительностью, второй - с объектами, используемыми для RAII: кто из них должен иметь право собственности?
Правильный конструктор Move решает 2 проблемы:
- Понятно, какой объект принадлежит: новый, так как оригинал будет удален
- Таким образом, нет необходимости копировать указанные ресурсы, что позволяет повысить эффективность
auto_ptr
и unique_ptr
являются очень хорошей иллюстрацией этого.
С auto_ptr
у вас есть семантическое копирование с завинчивающейся копией: оригинал и копия не сравниваются. Вы можете использовать его для семантики 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 может быть довольно слабым в применении стандарта, а также имеет ряд расширений, которые вам необходимо отключить, чтобы обеспечить переносимость кода ... не используйте его для проверки стандарта:)