Move semantics — это механизм C++, позволяющий эффективно переносить ресурсы между объектами, а не копировать их. С появлением C++11 введены перемещающие конструкторы и операторы присваивания, которые позволяют объектам передавать свои ресурсы другому объекту без затрат на копирование.
std::move превращает передаваемый объект в rvalue-ссылку, сигнализируя, что с ним можно безопасно переместить ресурсы. std::forward используется в шаблонах для сохранения типа значения (lvalue/rvalue) при передаче дальше.
#include <string> #include <vector> #include <iostream> std::vector<std::string> getNames() { std::vector<std::string> v = {"Alice", "Bob", "Charlie"}; return v; // Здесь сработает move semantics } int main() { std::vector<std::string> names = getNames(); // Здесь contents getNames() будут перемещены без лишнего копирования }
Чем отличается std::move от перемещающего конструктора? Если написать std::move, всегда ли переместится объект?
Ответ:
std::move — это всего лишь приведение к rvalue-ссылке, оно не выполняет само по себе перемещения. Перемещающая операция сработает только если действительно есть реализованный move-конструктор/оператор. В противном случае произойдет копирование.
struct A { A() = default; // нет move-конструктора A(const A&) { std::cout << "Copy! "; } }; A a1; A a2 = std::move(a1); // Вызывается копирование, не перемещение
История
-In одной из финансовых систем оптимизировали работу со строками, заменяя копирования на std::move, но структура не имела реализованных move-конструкторов. Копирование оставалось, производительность не выросла, возникла ложная уверенность в ускорении кода.
История
-Разработчик выполнил std::move() над переменной, которую продолжил использовать после перемещения. Данные оказались в неконсистентном состоянии, приложение периодически падало.
История
-В серверном библиотечном коде принимали временные объекты по const ссылка, а затем пытались std::move(), ожидая перемещения. Как результат — копирование, неэффективная работа и рост задержек при больших нагрузках.