Создание константной lvalue-ссылки из возврата по значению: как это работает?
Отсюда я узнал, что константная ссылка может быть сделана из объекта, возвращаемого значением функцией. Но теперь я спросил себя: куда поместить этот объект, чтобы он был безопасным и не перезаписывался стеками будущих вызовов функций?
Рассмотрим этот код:
#include <iostream>
using namespace std;
struct A{};
A returnsmt(){
int avariable;
cout<<"returnsmt stack: "<<&avariable<<endl;
return A();
}
const A& proxyreturnsmt(){
int avariable;
const A& middle=returnsmt();
cout<<"proxyreturnsmt stack: "<<&avariable<<" A ptr: "<<&middle<<endl;
return middle;
}
int main(){
int avariable;
const A& a=proxyreturnsmt();
cout<<"main stack: "<<&avariable<<" A ptr: "<<&a<<endl;
}
Теперь даже невозможно, чтобы main
знает, что он собирается создать ссылку из объекта стека, поэтому уловка не может заключаться в том, что он передает скрытый указатель на собственное ведро свободного стека. Этот код на g++ печатает:
returnsmt stack: 0x7fff3718bc0c
proxyreturnsmt stack: 0x7fff3718bc28 A ptr: 0x7fff3718bc2f
main stack: 0x7fff3718bc4c A ptr: 0x7fff3718bc2f
так что, если стек растет вниз, то место, где находится объект, proxyreturnsmt
стек Почему вы не столкнетесь с проблемами, если, получив эту справку, позвоните, скажем, function_with_big_stack_alloc
и так наверняка исправят старые proxyreturnsmt
стек для нового использования?
1 ответ
Программа демонстрирует неопределенное поведение. В proxyreturnsmt
связываешь middle
на временный объект. Время жизни этого временного объекта продлевается только до middle
выходит за рамки.
Затем вы возвращаете ссылку на middle
; но объект, на который он ссылается, уничтожается при возврате функции. Итак, в main
где вы связываете a
к результату звонка proxyreturnsmt
, a
является висячей ссылкой (объект, на который она ссылается, больше не существует).
Когда вы пытаетесь использовать ссылку (беря адрес ссылочного объекта, который больше не существует), программа демонстрирует неопределенное поведение.