Что такое std::move?

Ответ

std::move — это функция из заголовка <utility>, которая выполняет безусловное приведение переданного аргумента к rvalue-ссылке (T&&). Её основное назначение — явно указать компилятору, что объект можно рассматривать как перемещаемый, тем самым разрешив вызов move-конструктора или move-оператора присваивания вместо их копирующих аналогов.

Важно: std::move сама по себе не перемещает данные. Она лишь подготавливает объект к перемещению.

Пример:

#include <utility>
#include <vector>
#include <string>

int main() {
    std::vector<std::string> large_data = {"a", "very", "large", "collection", "of", "strings"};

    // Без std::move — вызов КОПИРУЮЩЕГО конструктора (дорого)
    std::vector<std::string> copy = large_data;

    // С std::move — вызов MOVE-конструктора (дешёвая операция)
    std::vector<std::string> moved = std::move(large_data);

    // После перемещения состояние 'large_data' валидно, но не определено.
    // Обычно он становится пустым, но полагаться можно только на то,
    // что его можно безопасно уничтожить или присвоить ему новое значение.
    return 0;
}

Ключевые моменты:

  1. Используйте std::move только тогда, когда вам больше не нужен исходный объект в его текущем состоянии.
  2. Для примитивных типов (int, char) std::move не даёт преимуществ, так как их перемещение эквивалентно копированию.
  3. std::move — это всего лишь каст. Фактическое перемещение происходит в конструкторе или операторе присваивания принимающего объекта.

Ответ 18+ 🔞

А, ну вот, опять про этот std::move спрашивают. Ёпта, народ как будто с луны свалился. Ладно, щас разжуём, как для самых маленьких, только без соплей.

Представь себе, есть у тебя здоровенный диван. И ты хочешь его перенести из одной комнаты в другую. Можно поступить по-дурацки: сфоткать его со всех ракурсов, заказать по чертежам точно такой же новый диван в другую комнату, а старый потом выкинуть. Это копирование, блядь. Дорого, долго, ресурсов жрёт овердохуища.

А можно взять и просто перетащить этот диван нахуй в соседнюю комнату. Старая комната пустая, новая — занятая. Это перемещение. Быстро, дёшево, всем хорошо. Так вот std::move — это не грузчики, которые тащат диван. Это ты такой подходишь к дивану, показываешь на него пальцем и говоришь компилятору: «Слушай, этот диван тут больше не нужен, его можно считать пустым и просто перетащить, а не копировать». Ты даёшь разрешение на перемещение, понимаешь? Фактическое «перетаскивание» делает уже move-конструктор или move-оператор присваивания того объекта, который этот диван принимает.

std::vector<std::string> мои_данные = {"тонны", "текста", "который", "не", "хочется", "копировать"};

// Тупой способ (копирование). Всё, пиши пропало, теперь у тебя два одинаковых здоровенных вектора.
std::vector<std::string> копия = мои_данные;

// Офигенный способ (перемещение). Ты сказал «этот вектор тут больше не жилец, забирай его потроха».
// После этой строки `мои_данные` — это как пустая коробка из-под дивана. Валидна, но внутри нихуя.
std::vector<std::string> перемещённый = std::move(мои_данные);

Главные правила, чтобы не обосраться:

  1. Используй только когда объект больше не нужен. Это как отдать последнюю рубашку. После std::move состояние исходного объекта — «не определено, но валидно». Чаще всего он становится пустым, но рассчитывать можно только на то, что его можно безболезненно удалить или присвоить ему что-то новое. Допустим, вызвать clear().
  2. На примитивах это бесполезно. Что толку «перемещать» int? Его копирование — это и так одна инструкция процессора. Тут std::move — просто мартышлюшка.
  3. std::move — это просто намёк, а не действие. Она не делает ровным счётом нихуя, кроме как превращает твой объект в rvalue-ссылку (T&&). Вся магия происходит потом, в коде того, кто этот «перемещённый» объект принимает. Если у принимающего типа нет move-конструктора, то вызовется обычный копирующий, и будет тебе пизда рулю вместо оптимизации.

Короче, std::move — это твой способ сказать компилятору: «Чувак, вот этот объект — хуй с горы, забирай его как есть, мне он больше не нужен». Если врать не будешь и будешь использовать это только для тяжёлых, одноразовых объектов — будет тебе счастье и производительность. Если начнёшь двигать всё подряд, включая свои же живые данные — получишь хитрожопые баги и будешь потом ночами дебажить, ебать колотить.