Ссылка на временный объект.
Прямо (
int&& d = 5
) используется крайне редко, чтобы продлить время жизни временному объекту.
Куда чаще оно используется в типах возврата (
string&& Container::give()
), и означает: это ссылка на объект, который спокойно можно выпотрошить. Или в типах параметров —
Container& Container::operator = (string&& x)
: то есть принимает объект, который больше не нужен.
Для чего потрошить объекты? Вот представьте себе код.
std::vector<int> doSmth() {
std::vector<int> r;
r.push_back(42);
return r;
}
...
std::vector<int> a = doSmth();
Забьём на необязательные оптимизации — как эта штука будет действовать по семантике Крестов?
std::vector<int> r;
— создадим в стековом фрейме переменную r.
return r;
— vector(const vector&) в какое-то место, предложенное вызывающей функцией.
std::vector<int> a = doSmth();
— vector(const vector&) из этого места в a.
Си++17 ТРЕБУЕТ, чтобы подобный возврат гарантированно вызывал ОДИН конструктор копирования (а если конструировать на месте вроде
return vector<int>{ 42 };
— то ни одного), но у нас-то Си++03. Не много конструкторов? А ведь зная, что объект больше не нужен, можем просто перенести указатель из одного вектора в другой, точка — даже впрямую, без оптимизаций, никаких перевыделений памяти. Вот этот прямой перенос указателей я и назвал словом «выпотрошить объект».
Пример 1:
container = string("alpha") + "bravo";
Тут в контейнер перемещается временная строка.
Пример 2:
string a = "alpha"; container = a;
Не компилируется: строка a не временная.
Пример 3.
container1 = container2.give();
Перенос строки из контейнера в контейнер без выделения памяти.
Пример 4:
string a = "alpha"; container = std::move(a);
Компилируется (мы функцией move сказали: с обычным объектом обращаться как с временным), но в результате в строке a может быть что угодно и не стоит закладываться на дальнейшее её значение. Но объект после потрошения в любом случае должен быть корректным, ведь ему ещё вызывать деструктор :)
Последний вопрос: кто потрошит? Функция, которая принимает временную ссылку как параметр. В данном случае Container::op=. Чем потрошит? — ну, например, кодом
myString=std::move(x)
или
std::swap(myString, x)
. А они, в свою очередь — внутренняя string::op= и дружественная swap — прямыми играми с указателями.