Перейти к содержанию

Введение в семантику перемещения

Начало урока

Введение в семантику перемещения

Перестаньте копировать то, что можно забрать — как современный C++ перемещает ресурсы вместо их дублирования.

Главная идея: Когда объект владеет дорогим ресурсом (буфером в куче, файловым дескриптором, большим std::vector), копирование дублирует этот ресурс байт за байтом. Перемещение же передаёт владение существующим ресурсом новому объекту, оставляя старый пустым. Тот же результат — за долю усилий. Семантика перемещения — это возможность языка (появилась в C++11 и совершенствуется с тех пор), которая делает это безопасным и автоматическим.
К концу урока вы сможете:
  • отличать lvalue от rvalue и объяснять, почему это различие важно,
  • описывать, чего стоит копирование и как перемещение его избегает,
  • правильно использовать std::move — и объяснять, что сам по себе он ничего не перемещает,
  • рассуждать о состоянии объекта после того, как из него переместили,
  • распознавать, где компилятор перемещает за вас автоматически (возвраты, вставка в контейнеры).

1. lvalue против rvalue: есть ли у него имя, на которое можно указать?

Каждое выражение в C++ является либо lvalue, либо rvalue (есть и более тонкие категории, но эти две передают суть). Названия происходят от сторон присваивания: исторически lvalue могло стоять слева от =, а rvalue — только справа.

  • lvalue — это объект со стабильной идентичностью: именованное место в памяти, у которого можно взять адрес. Переменные — это lvalue: x, account.balance, numbers[3].
  • rvalue — это временное значение без постоянного имени, результат выражения, которое вот-вот исчезнет. Литералы и результаты большинства выражений — это rvalue: 42, a + b, std::string("hi"), значение, возвращаемое функцией.

Практический тест: если у него можно взять адрес через & — это lvalue; если нельзя — это rvalue.

int x = 10;
int& a = x;          // OK: x - lvalue, у него есть адрес
// int& b = 10;      // ОШИБКА: 10 - rvalue, адреса для привязки нет
int&& c = 10;        // OK: rvalue-ССЫЛКА может привязаться к временному 10
int&& d = x + 5;     // OK: (x + 5) - временное rvalue

Последний фрагмент синтаксиса — int&&, двойной амперсанд — это rvalue-ссылка. Это ссылка, которая привязывается только к rvalue (временным). Именно на этом держится семантика перемещения: функция может предложить одну перегрузку для const T& (привязывается к чему угодно, обещает не менять) и другую для T&& (привязывается только к временным, которые вызывающему больше не нужны). Когда выбрана вторая, функция знает, что забрать содержимое аргумента безопасно.

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

Продолжите этот урок на YourAIZone

В полном уроке — объяснение целиком, разобранные примеры, частые ошибки, тесты с мгновенной проверкой и ИИ-репетитор. Начните сразу как гость или создайте аккаунт, чтобы сохранять прогресс.

В полном уроке

  • Объяснение целиком
  • Разобранные примеры
  • Частые ошибки и как их избежать
  • Тестовые вопросы: 15
  • ИИ-репетитор, который отвечает на вопросы по теме
  • Отслеживание прогресса для ученика, родителей и учителя