указатель this от временного объекта

есть такой надуманный класс для примера

class Example
{
public:
  int x = 0;
  Example& get_ref()
  {
    return *this;
  }
};

такая строчка естественно вызывает ошибку, так как берем неконстантную ссылку на rvalue

Example& example = Example();

но почему такой пример не вызывает ошибок и мы можем даже менять состояние по этой ссылке, если это тоже самое? (или не тоже самое?)

Example& example = Example().get_ref();

и каким образом указатель this берет адрес временных объектов? я себе представлял это так под капотом Example* this = &(объект вызывающий метод) и не задумывался особо, так как никогда не вызывал методы от rvalue или вызывал и не думал об этом...


Ответы (2 шт):

Автор решения: AR Hovsepyan

Выражением Example& example = Example(); вы ссылаетесь на несуществующий объект, то есть левый операнд есть ссылка, а правый _ объект. А в выражении:

Example& example = Example().get_ref();

И первое и второе выражение есть ссылки, поэтому это не то же самое и не является ошибкой. Другое дело, что объекта нет после этого выражения. Ну это как бы то же самое, что написать:

Example* pex = new Example;
Example& example = *pex; // *pex тоже является ссылкой на объект
delete pex;

Как вы понимаете, после этого кода ссылка становится недействительной

→ Ссылка
Автор решения: HolyBlackCat

Во втором примере временный объект сразу же удаляется, потому если дальше работать со ссылкой, то будет UB.

каким образом указатель this берет адрес временных объектов?

Ну просто берет. Невозможность напрямую взять адрес rvalue1 - это защита от дурака, искусственное ограничение.


Еще, полезно понять разницу между объектами и выражениями.

Объект создается во время выполнения (где-то в памяти), а выражение - это надпись в коде, ссылающаяся на этот объект.

Вот вы выполнили Example().get_ref();, и в памяти создался временный объект. Выражение Example() ссылается на этот объект, и это выражение является rvalue.

Внутри метода get_ref(), выражение *this ссылается на тот же самый объект, это выражение является lvalue.

Категории (lvalue/rvalue/...) есть только у выражений, у объектов их нет. Адреса есть у всех объектов2, даже у временных.


1 Точнее, взять адрес xvalue. У prvalue адреса как такового нет, но его можно материализовать в xvalue, у которого адрес есть. У вас prvalue Example() материализуется, когда на нем дергают метод.

2 Тут можно поспорить, а что есть объект в регистре? Стандарт разрешает получить адрес любого объекта (даже временного - но не напрямую, а например внутри метода, как вы сделали). Для вас все объекты как будто бы находятся в памяти. Компилятор может засовывать их в регистры только по as-if rule - то есть если компилятор решил поместить объект в регистр, то он должен делать это незаметно для вас.

→ Ссылка