Namespaces
Variants

std:: move

From cppreference.net
Utilities library
Определено в заголовочном файле <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-аргументами (либо prvalues , таких как временные объекты, либо xvalues , таких как создаваемые с помощью std::move ). Если аргумент идентифицирует объект, владеющий ресурсами, эти перегрузки имеют возможность, но не обязаны, перемещать любые ресурсы, удерживаемые аргументом. Например, конструктор перемещения связного списка может скопировать указатель на голову списка и сохранить nullptr в аргументе вместо выделения памяти и копирования отдельных узлов.

Имена переменных rvalue reference являются lvalues и должны быть преобразованы в xvalues для привязки к перегрузкам функций, принимающим параметры rvalue reference, поэтому move constructors и move assignment operators обычно используют std::move :

// Простой конструктор перемещения
A(A&& arg) : member(std::move(arg.member)) // выражение "arg.member" является lvalue
{}
// Простой оператор перемещающего присваивания
A& operator=(A&& other)
{
    member = std::move(other.member);
    return *this;
}

Одним исключением является случай, когда тип параметра функции представляет собой forwarding reference (которая выглядит как rvalue-ссылка на параметр шаблона типа), в этом случае вместо этого используется std::forward .

Если не указано иное, все объекты стандартной библиотеки, из которых было выполнено перемещение, помещаются в «валидное, но неопределённое состояние», означающее, что инварианты класса объекта сохраняются (таким образом, функции без предусловий, такие как оператор присваивания, могут быть безопасно использованы для объекта после перемещения из него):

std::vector<std::string> v;
std::string str = "example";
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 = "Salut";
    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 = "Salut"
После перемещения, str = ""
Содержимое вектора: {"Salut", "Salut"}

Смотрите также

(C++11)
перенаправляет аргумент функции и использует тип шаблона для сохранения его категории значения
(шаблон функции)
преобразует аргумент в xvalue, если конструктор перемещения не генерирует исключений
(шаблон функции)
(C++11)
перемещает диапазон элементов в новое местоположение
(шаблон функции)