Предположим, у нас есть функция, которая возвращает значение:
int func() {
int x = 10; // create local variable x with value of 5
return x; // create temporary copy of x which is returned, local variable x is destroyed
}
int main()
{
int y = func(); // temporary copy of x is copied to y, when it hits`;` the temporary object is destroyed
return 0;
}
Поправьте меня, если я ошибаюсь в чем-то, что я сказал в комментариях выше.
Теперь мы можем продлить срок службы временного объекта, просто сделав постоянную ссылку на него.
int main()
{
const int & y = func(); // now the temporary object (R-value) is not destroyed when it hits `;` thus the life time is lenghtened.
return 0;
}
Вопрос в том, что поскольку я создал постоянную ссылку на временный объект, который должен быть уничтожен, означает ли это, что cout << &y << endl
будет печатать адрес этого временного объекта, так как ссылка это просто «псевдоним»? Также, где эти временные объекты (R-значения) хранятся в памяти (я использовал примитивный тип int, но это может быть класс)?
Как уже указывалось в комментариях, создание ссылки на const (или ссылку на rvalue) на временную ссылку продлевает срок ее службы до той, что указана для ссылки.
Также, где эти временные объекты (R-значения) хранятся в памяти (я
использовал примитивный тип int, но это может быть класс)?
Это не указано в стандарте. Тем не менее, вы можете просто проверить наиболее распространенные компиляторы, что они будут делать. Начиная с GCC, без каких-либо оптимизаций, вы получите
func():
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-4], 10
mov eax, DWORD PTR [rbp-4]
pop rbp
ret
main:
push rbp
mov rbp, rsp
sub rsp, 16
call func()
mov DWORD PTR [rbp-12], eax
lea rax, [rbp-12]
mov QWORD PTR [rbp-8], rax
mov eax, 0
leave
ret
Таким образом, возвращаемое значение помещается в регистр EAX внутри функции, и как только оно возвращается, значение помещается в кадр стека main (), как если бы вы создали переменную в функции main. Вы найдете похожие результаты с другими компиляторами. При включении оптимизаций, очевидно, произойдет очевидное: компилятор видит, что функция просто возвращает некоторое постоянное значение и полностью его исключает:
func():
mov eax, 10
ret
.LC0:
.string "%i"main:
sub rsp, 24
mov edi, OFFSET FLAT:.LC0
xor eax, eax
lea rsi, [rsp+12]
mov DWORD PTR [rsp+12], 10
call printf
xor eax, eax
add rsp, 24
ret
Здесь я добавил несколько вызовов printf (), которые выведут адрес временного s.t. программа не совсем тривиальна.
Таким образом, он создает функцию, но не будет вызывать ее и просто записывает 10 снова в некоторое пространство в кадре локального стека. Если вы просто используете его по значению, он будет просто внесен в регистр, так как адрес не требуется.
Других решений пока нет …