0Pricing
C++ Academy · Урок

std::move и std::forward

Преобразуйте lvalue в rvalue с помощью std::move и сохраняйте категорию значения с помощью std::forward.

«std::move и std::forward» — бесплатный урок C++ Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C++ Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C++ Academy содержит 4 уроков всего.

Два близких инструмента для разных задач

std::move и std::forward — это приведения типов на этапе компиляции. Они похожи, но решают разные задачи.

std::move: всегда приведение к правостороннему значению

std::move(x) безусловно приводит x к ссылке на правостороннее значение. После этого принимающая функция может забрать его ресурсы.

std::string s = "Hello";
std::string t = std::move(s);   // move-constructs t from s
// s is now in a valid-but-unspecified state

Когда использовать move

Используйте std::move в следующих случаях:

  • в конструкторах перемещения и операторах присваивания с перемещением
  • при возврате локальной переменной, если нужно принудительно выполнить перемещение (требуется редко — обычно применяется RVO)
  • при передаче локального объекта, который больше не нужен, функции-приёмнику

Реализация std::move

На самом деле это всего лишь замаскированный static_cast:

template <typename T>
typename std::remove_reference<T>::type&& move(T&& t) noexcept {
    return static_cast<typename std::remove_reference<T>::type&&>(t);
}

std::forward: сохранение категории

В шаблоне, использующем передающую ссылку (T&&), std::forward<T>(x) возвращает x к его исходной категории (левостороннее или правостороннее значение). Используется для идеальной передачи.

template <typename T>
void wrapper(T&& arg) {
    target(std::forward<T>(arg));  // forwards as lvalue or rvalue depending on T
}

Зачем нужна передача

Внутри шаблона параметр имеет имя, поэтому является левосторонним значением, даже если вызывающий код передал правостороннее значение. std::forward восстанавливает исходную категорию.

Без std::forward

Без forward каждый аргумент внутри wrapper передавался бы как левостороннее значение, из-за чего терялась бы семантика перемещения, предусмотренная вызывающим кодом.

template <typename T>
void wrapper(T&& arg) {
    target(arg);    // always lvalue — wrong
}

Всегда указывайте параметр шаблона для forward

std::forward<T> требует явного аргумента шаблона. Без него поведение было бы некорректным.

Пример идеальной передачи

Фабричная функция, передающая аргументы конструктора, сохраняет различия между правосторонними и левосторонними значениями для повышения эффективности.

template <typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args) {
    return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}

Перемещайте только один раз

Каждый объект следует перемещать не более одного раза. После перемещения он находится в допустимом, но не определённом состоянии — обычно его повторно присваивают или уничтожают. Использование объекта после перемещения без предварительного присваивания может привести к трудноуловимым ошибкам.

Практические правила

Краткая мысленная модель:

  • у вас есть конкретный тип и вы хотите переместить объект → std::move
  • у вас есть параметр шаблона и вы хотите сохранить категорию значения → std::forward<T>

Быстрая проверка

Как внутри шаблонной функции с параметром T&& arg передать arg, сохранив его категорию — левостороннее или правостороннее значение?

Итоги

std::move безусловно приводит к правостороннему значению — используйте его для конкретных объектов, ресурсы которых нужно забрать. std::forward<T> сохраняет категорию значения внутри универсальных шаблонов — используйте его для идеальной передачи.

Часто задаваемые вопросы

Урок «std::move и std::forward» бесплатный?

Да — полный текст урока «std::move и std::forward» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C++ Academy, подпишись на CoddyKit PRO. Курс C++ Academy содержит 4 уроков всего.

Чему я научусь в уроке «std::move и std::forward»?

Преобразуйте lvalue в rvalue с помощью std::move и сохраняйте категорию значения с помощью std::forward. Ты практикуешь C++ Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать C++ Academy?

Предыдущий опыт не требуется. C++ Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.

Сколько времени занимает урок «std::move и std::forward»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке C++ Academy?

Да. Каждый урок C++ Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Lvalue и rvalue: различие
  2. Ссылки rvalue и синтаксис &&
  3. std::move и std::forward
  4. Конструкторы перемещения и присваивание перемещением
← Назад к C++ Academy