
Move‑семантика в C++: пять задач, в которых легко ошибиться
badcasedaily1 16 минут назад Move‑семантика в C++: пять задач, в которых легко ошибиться Средний 9 мин 783 Блог компании OTUS C++ * Программирование * Системное программирование * Туториал Привет, Хабр! Move‑семантика в...
Anthropic — What company has the best second artificial intelligence model at the end of June?
Значимый прорыв формирует отрасль ИИ: badcasedaily1 16 минут назад Move‑семантика в C++: пять задач, в которых легко ошибиться Средний 9 мин 783 Блог компании OTUS C++ * Программирование * Системное программирование * Туториал Привет, Хабр! Move‑семантика в C++ давно стала повседневной частью языка, но в код‑ревью регулярно всплывают тонкости, на которых ошибаются даже опытные разработчики: лишний std::move в return, забытый noexcept на move‑конструкторе, неработающее перемещение из const‑объекта. Все эти ошибки компилируются без предупреждений, иногда без warnings даже с флагами -Wall -Wextra, и проявляются либо медленным кодом, либо тихим undefined behavior.
Сегодня разберём пять задач на самые частые ловушки move‑семантики. Попробуйте сначала ответить сами, потом сверьтесь с разбором. Задача 1: лишний std::move в returnДан простой код, возвращающий вектор по значению:std::vector create_data(size_t n) { std::vector result; result.
Технические детали
reserve(n); for (size_t i = 0; i < n; ++i) { result. push_back(static_cast(i * i)); } return std::move(result); }Вопрос: что не так с return std::move(result) и как этот код повлияет на производительность по сравнению с обычным return result? Когда функция возвращает локальную переменную по значению, компилятор имеет право применить named return value optimization (NRVO).
Это оптимизация, при которой объект сразу конструируется в памяти вызывающей стороны, без отдельного шага перемещения или копирования. С C++17 для определённых случаев copy elision стал обязательным, для NRVO он остался разрешённым, но не гарантированным. std::move принимает аргумент по lvalue‑ссылке и возвращает rvalue‑ссылку.
Когда return получает не саму локальную переменную, а результат функции std::move, NRVO становится недоступным: компилятор больше не видит возврат именованного локального объекта, он видит возврат rvalue, для которого NRVO не применяется. В лучшем случае произойдёт move‑конструирование, в худшем для типов без move‑конструктора будет копирование. Для std::vector это пара лишних указателей и атомарная операция в аллокаторе, что почти незаметно.
Отраслевые последствия
Для типа с дорогим move‑конструктором или для типа, у которого move‑конструктор удалён, а NRVO бы сработал, разница станет ощутимой. Правило простое: возвращайте локальные объекты как есть, без std::move, доверяйте компилятору. Современные компиляторы под -Wpessimizing-move (GCC, Clang) выдают предупреждение на такой код.
Задача 2: self‑move‑assignmentКласс управляет динамическим буфером и реализует move‑assignment:class Buffer { public: Buffer(size_t size) : size_(size), data_(new char) {} ~Buffer() { delete data_; } Buffer(Buffer&& other) noexcept : size_(other. data_ = nullptr; other.
Этот прогресс даёт важные сигналы о будущем отрасли, и технологический мир внимательно наблюдает.





