Ответ
Move-семантика — это механизм в C++ (начиная с C++11), который позволяет эффективно передавать владение ресурсами (например, динамической памятью) от одного объекта к другому, избегая дорогостоящих глубоких копий. Она основана на использовании rvalue-ссылок (&&).
Ключевые компоненты:
- Rvalue-ссылки (
T&&): Ссылаются на временные объекты (rvalues), что позволяет их "опустошать". - Move-конструктор и move-оператор присваивания: Специальные члены класса, которые "крадут" ресурсы у исходного объекта.
std::move: Утилита из<utility>, которая приводит lvalue к rvalue, сигнализируя о том, что объект можно переместить.
Пример класса с move-семантикой:
#include <utility>
class Buffer {
int* data_;
size_t size_;
public:
// Move-конструктор
Buffer(Buffer&& other) noexcept
: data_(std::exchange(other.data_, nullptr))
, size_(std::exchange(other.size_, 0)) {}
// Move-оператор присваивания
Buffer& operator=(Buffer&& other) noexcept {
if (this != &other) {
delete[] data_; // Освобождаем свои старые ресурсы
data_ = std::exchange(other.data_, nullptr);
size_ = std::exchange(other.size_, 0);
}
return *this;
}
~Buffer() { delete[] data_; }
// ... (конструктор копирования, обычный конструктор и т.д.)
};
// Использование
Buffer createBuffer(size_t n); // Фабричная функция
Buffer b1(1024);
Buffer b2 = std::move(b1); // Вызов move-конструктора, b1 теперь пуст
Buffer b3 = createBuffer(512); // Move-конструктор (возвращаемое значение — rvalue)
Важные правила:
- Move-операции должны быть помечены
noexcept(особенно для совместимости с контейнерами STL, например, приvector::resize). - После перемещения исходный объект должен находиться в валидном, но неопределенном состоянии (его можно безопасно уничтожить или присвоить ему новое значение).
- Компилятор может сгенерировать move-операции по умолчанию, если в классе нет пользовательских копирующих операций, перемещающих операций или деструктора.
- Move-семантика лежит в основе оптимизаций, таких как copy elision и Return Value Optimization (RVO).