Я обычно понимаю, как функция возвращает объект по значению. Но я хотел понять это на более низком уровне. Уровень сборки, если это разумно.
Я понимаю этот код
ClassA fun(){
ClassA a;
a.set(...);
return a;
}
внутренне преобразуется в
void fun(Class& ret){
ClassA a;
a.set(...);
ret.ClassA::ClassA(a);
}
Который эффективно вызывает конструктор копирования по возвращаемому значению.
Я также понимаю, что есть некоторые оптимизации (например, NRVO), которые могут генерировать следующий код, избегая конструктора копирования.
void fun(Class& ret){
ret.set(...);
}
Однако мой вопрос немного более общий. Это не связано с конкретными объектами. Это могут быть даже примитивные типы.
Предположим, что у нас есть этот код:
int fun(){
return 0;
}
int main(){
fun();
}
Мой вопрос в том, где находится возвращаемый объект, хранящийся в памяти.
Если мы посмотрим на стек... Существует стек стека main
, а затем фрейм стека fun
. Является ли возвращаемый объект сохраненным в некотором адресе, например, между двумя фреймами стека? Или, возможно, он хранится где-то в кадре стека main
(и, возможно, тот адрес, который передается по ссылке в сгенерированном коде).
Я подумал об этом, и второй кажется более практичным, но я не понимаю, как компилятор знает, сколько памяти нужно вставить в стек кадров main
? Рассчитывает ли он самый большой тип возврата и толкает его, хотя может быть какая-то потерянная память? Или это выполняется динамически, оно выделяет это пространство только до того, как вызывается функция?