Последнее обновление:2026-10-12
Принцип работы и применение std::move в C++¶
std::move — это очень важная функция, предоставляющая способ пометить lvalue-объект как особый тип rvalue-объекта, а именно xvalue. Такое преобразование нужно, чтобы дать возможность выполнить move-семантику вместо обычной семантики копирования.
- Зачем использовать std::move
- Практические сценарии применения
1.Зачем использовать std::move¶
Обычно перемещать можно только rvalue-объекты, поскольку move-конструктор принимает rvalue-ссылку в качестве параметра, а rvalue-ссылка может привязываться только к rvalue. Поэтому, если вы хотите выполнить перемещение из объекта, представленного lvalue-выражением, вам нужно с помощью std::move преобразовать его в xvalue (особый вид rvalue).
Использовать std::move следует осторожно, поскольку после перемещения объект оказывается в состоянии, в котором допускается, по сути, только его уничтожение. Поэтому лучше всего выполнять перемещение только при последнем использовании объекта.
std::move не выполняет перемещение на самом деле. Важно понимать: std::move не производит фактического перемещения объекта. Она лишь преобразует данный lvalue-объект в rvalue-ссылку. Ниже приведена одна из возможных реализаций std::move:
template <typename T>
typename remove_reference<T>::type&& move(T&& t)
{
return static_cast<typename remove_reference<T>::type&&>(t);
}
2.Практические сценарии применения¶
2.1 Move-конструктор вместо копирующего конструктора¶
В функции f1 параметр a — это lvalue с типом rvalue-ссылки, а не само rvalue, поскольку у него есть имя. Поэтому, чтобы задействовать move-конструктор Foo, мы должны преобразовать его в rvalue, и std::move отлично подходит для этого.
struct Foo {
...
Foo(const Foo&) {}
Foo(Foo&&) {}
};
void f1(Foo&& a) {
Foo b(a); // 调用拷贝构造函数,而非移动构造函数
}
void f2(Foo&& a) {
Foo b(std::move(a)); // right
}
2.2 Управление владением¶
Предположим, есть такой код:
Этот код работает, но вы не можете определить, кому принадлежит указатель. Кто должен удалить указатель? Или когда указатель должен быть удалён? Будет ли он удалён при уничтожении контейнера?
В C++11 инструкция std::unique_ptr<Foo> p(new Foo()); приведёт к ошибке компиляции. Причина в том, что действует правило единоличного владения.
Однако вы можете использовать std::move, чтобы передать владение указателем:
Теперь владение указателем передано контейнеру, и указатель будет удалён по окончании времени жизни контейнера. Хотя объект p всё ещё существует, любая попытка разыменовать его приведёт к исключению из-за нулевого указателя.
Фактически после операции перемещения внутренний указатель, которым владел p, уже установлен в nullptr.
Подводя итог: роль std::move в том, что она предоставляет средство безопасно реализовать move-семантику объекта, превращая его lvalue-свойство в rvalue, чтобы объект мог быть передан в move-конструктор или move-оператор присваивания. Правильное использование std::move повышает производительность и обеспечивает корректную передачу владения.
Тогда следующий вопрос: когда std::move использовать не нужно?
Похожие темы¶
- Обзор новых возможностей C++11 | C++那些事
- Сравнение std::bind и lambda в C++ | C++那些事
- Вариативные шаблоны в C++ | C++那些事