std::move
| Определено в заголовочном файле <utility>
|
||
template< class T > typename std::remove_reference<T>::type&& move( T&& t ) noexcept; |
(начиная с C++11) (до C++14) |
|
template< class T > constexpr std::remove_reference_t<T>&& move( T&& t ) noexcept; |
(начиная с C++14) | |
std::move используется для указания того, что объект t может быть "перемещён из", т.е. позволяет эффективно передавать ресурсы из t в другой объект.
В частности, std::move создаёт выражение xvalue, которое идентифицирует его аргумент t. Это в точности эквивалентно static_cast ссылочного типа rvalue.
Параметры
| t | — | объект, который нужно переместить |
Возвращаемое значение
static_cast<typename std::remove_reference<T>::type&&>(t)
Примечание
Функции, которые принимают ссылочные параметры rvalue (включая конструкторы перемещения, операторы присваивания перемещением и обычные функции-элементы, такие как std::vector::push_back) выбираются разрешением перегрузки, когда вызываются с аргументами rvalue (либо значениями prvalue такими как временный объект, либо значениями xvalue, такими как созданные std::move). Если аргумент идентифицирует объект, владеющий ресурсами, эти перегрузки могут, но не обязательно, перемещать любые ресурсы, удерживаемые аргументом. Например, конструктор перемещения связанного списка может скопировать указатель на начало списка и сохранить nullptr в аргументе вместо выделения и копирования отдельных узлов.
Имена ссылочных переменных rvalue являются значениями lvalue и должны быть преобразованы в значения xvalue для привязки к перегрузкам функций, которые принимают ссылочные параметры rvalue, поэтому конструкторы перемещения и операторы присваивания перемещением обычно используют std::move:
// Простой конструктор перемещения
A(A&& arg) : member(std::move(arg.member)) // выражение "arg.member" равно lvalue
{}
// Простой оператор присваивания перемещением
A& operator=(A&& other) {
member = std::move(other.member);
return *this;
}
Единственным исключением является случай, когда тип параметра функции является ссылкой rvalue на параметр шаблона типа ("пересылаемая ссылка" или "универсальная ссылка"), и в этом случае вместо этого используется std::forward.
Если не указано иное, все объекты стандартной библиотеки, из которых было перемещение, помещаются в "допустимое, но неопределённое состояние", что означает сохранение инвариантов объекта класса (поэтому функции без предварительных условий, такие как оператор присваивания, можно безопасно использовать с объектом после перемещения):
std::vector<std::string> v;
std::string str = "пример";
v.push_back(std::move(str)); // str теперь действителен, но не определён
str.back(); // неопределённое поведение, если size() == 0:
// back() имеет предварительное условие !empty()
if (!str.empty())
str.back(); // OK, у empty() нет предусловия, а предусловие back() выполнено
str.clear(); // OK, у clear() нет предусловий
Кроме того, стандартные библиотечные функции, вызываемые с аргументами xvalue, могут предполагать, что аргумент является единственной ссылкой на объект; если он был создан из lvalue с помощью std::move, проверки псевдонимов не выполняются. Однако самоприсваивание перемещением типов стандартных библиотек гарантированно переводит объект в допустимое (но обычно неопределённое) состояние:
std::vector<int> v = {2, 3, 3};
v = std::move(v); // значение v не указано
Пример
#include <iomanip>
#include <iostream>
#include <string>
#include <utility>
#include <vector>
int main()
{
std::string str = "Салют";
std::vector<std::string> v;
// использует перегрузку push_back(const T&), что означает,
// что мы понесём затраты на копирование str
v.push_back(str);
std::cout << "После копирования str равен " << std::quoted(str) << '\n';
// использует перегрузку push_back(T&&) со ссылкой на rvalue,
// что означает, что строки не будут скопированы; вместо
// этого содержимое str будет перемещено в вектор. Это дешевле,
// но также означает, что str теперь может быть пустым.
v.push_back(std::move(str));
std::cout << "После перемещения str равен " << std::quoted(str) << '\n';
std::cout << "Содержимое вектора равно { " << std::quoted(v[0])
<< ", " << std::quoted(v[1]) << " }\n";
}
Возможный вывод:
После копирования str равен "Салют"
После перемещения str равен ""
Содержимое вектора равно { "Салют", "Салют" }
Смотрите также
(C++11) |
пересылает аргумент функции (шаблон функции) |
(C++11) |
получает ссылку rvalue, если конструктор перемещения не генерирует исключение (шаблон функции) |
(C++11) |
перемещает диапазон элементов в новое место (шаблон функции) |