В C++ lvalue (left value) — это выражение, ссылающееся на объект в памяти, у которого есть имя и на который можно ссылаться (например, переменная). rvalue (right value) — это временное значение, не имеющее имени, и не являющееся объектом в традиционном смысле (например, результат a + b, литералы типа 5).
Lvalue можно брать по адресу, а rvalue — нет (до появления rvalue-ссылок). Для передачи их в функции существуют:
void foo(const std::string& s); — принимают lvalue и rvalue.void bar(std::string& s); — принимают только lvalue.void baz(std::string&& s); — принимают только rvalue.Пример:
void takeValue(std::string& s) { } // lvalue void takeRValue(std::string&& s) { } // rvalue std::string s = "hello"; takeValue(s); // OK, lvalue takeRValue(std::string("hi")); // OK, rvalue
rvalue-ссылки нужны для эффективной передачи временных объектов, главным образом для move-семантики, чтобы перемещать ресурсы, а не копировать их.
Какой тип ссылки (lvalue или rvalue) получит выражение
std::move(obj)? Какой категории станет сам объект после применения std::move?
Ответ:
std::move(obj) всегда возвращает rvalue-ссылку (T&&), но сам объект остаётся lvalue, просто к нему применяется явное преобразование. После этого с объектом надо обращаться крайне осторожно (он может быть в неопределённом, но валидном состоянии).
Пример:
std::string s = "data"; std::string d = std::move(s); // d получает данные s, s теперь пустой
История
В крупном проекте один из разработчиков передавал временные объекты через lvalue-ссылку T& (вместо T&& или const T&). Это приводило к компиляционным ошибкам и неоптимальным копированиям — move-семантика не использовалась, производительность снизилась на 40%.
История
Во фронтенд-движке неверно применяли std::move к переменным, которые после этого использовали снова. Из-за этого переменные были в "разрушенном" состоянии, вызывались аварийные завершения и крашились рендер-потоки.
История
В библиотеке сериализации передавали контейнер типа std::vector<T> в функцию как lvalue, а ожидали move. Вместо перемещения шло дорогое копирование большого количества элементов, что резко ухудшило время сериализации на больших массивах.