@FaulerAffe
-

Для чего нужна двойная ссылка &&?

На данный момент я ссылку понимаю так:
int a = 5;
int& b = a;

В таком коде мы как бы создаём псевдоним для a, который называется b. То есть обе эти переменные указывают на одну и ту же область памяти, у этих переменных одинаковый адрес.
Такая логика плюс-минус работает с такой записью:
const int& c = 5;
Я представляю это так: 5 находится в области памяти, записать в которую мы ничего не можем (из-за этого мы не можем написать, допустим, 5 = a), но при этом мы можем из этой области читать. Получается, что запись без const опасна - мы рискуем изменить что-то в этой памяти, а с const всё хорошо - мы создали псевдоним для области памяти, которую мы можем только читать.
А вот это что такое и какой у этого смысл, я не могу понять:
int&& d = 5;
Псевдоним для псевдонима... не могу понять. Чувствуется потребность в знании языка ассемблера, но я хотел бы для начала основы понять.
  • Вопрос задан
  • 512 просмотров
Решения вопроса 1
@Mercury13
Программист на «си с крестами» и не только
Ссылка на временный объект.

Прямо (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 — прямыми играми с указателями.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
Это называется rvalue reference
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы