std::move
Определено в заголовочном файле <utility> | ||
template<class T > typenamestd::remove_reference<T>::type&& move( T&& t )noexcept; | (начиная с C++11) (до C++14) | |
template<class T > constexprstd::remove_reference_t<T>&& move( T&& t )noexcept; | (начиная с C++14) | |
std::move
используется для указания того, что объект t может быть "перемещён из", т.е. позволяет эффективно передавать ресурсы из t в другой объект.
В частности, std::move
создаёт выражение xvalue, которое идентифицирует его аргумент t. Это в точности эквивалентно static_cast
ссылочного типа rvalue.
Содержание |
[править]Параметры
t | — | объект, который нужно переместить |
[править]Возвращаемое значение
static_cast<typenamestd::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) | перемещает диапазон элементов в новое место (шаблон функции) |