Мне было интересно, возможны ли когда-либо эти сценарии для компилятора?
Сначала мы определяем SomeDataType как:
struct SomeDataType{
public:
int a;
int b;
int c;
};
Сценарий № 1_относительно вызываемой функции, имеющей ссылочный параметр, подобный этому:
void doSomething(SomeDataType & input){
...
}
предполагая, что функция не является встроенной, и только переменные в областях функций вызывающей стороны передаются этой функции в программе и учитывая тот факт, что ссылки не обязательно являются указателями, часть памяти, в которой размещается входной аргумент, разделяется между кадрами стека любой вызывающей функции и стекового фрейма вызываемой функции «doSomething», так что «doSomething» может обращаться к этому параметру точно так же, как он обращается к любой локальной переменной в своей локальной области видимости, добавляя смещение к базовому указателю, который определяет начальный адрес его стека Рамка.
Сценарий № 2_Это кажется более невероятным для меня, но в любом случае; относительно функции вызываемого, которая возвращает структуру типа «SomeDataType»:
SomeDataType doSomething(){
SomeDataType someStruct;
...
return someStruct;
};
часть памяти, в которой находится структура «someStruct», распределяется между фреймом стека любого вызывающего и стековым фреймом вызываемой функции «doSomething», с учетом следующего выражения в функции вызывающей стороны:
SomeDataType TheStruct=doSomething();
в области действия этого вызывающего абонента использование «TheStruct» приводит к использованию той же части памяти, где находится «SomeStruct» в области действия вызываемого абонента, что означает, что в основном функция вызываемого абонента нигде не копирует «someStruct», и даже если копирование было необходимо, например, когда был оператор, подобный приведенному ниже, в функции вызывающей стороны, указывающий, что назначение не является структурой в области действия вызывающей стороны:
*pntrToSomewhere=doSomething();
это будет обязанностью вызывающей стороны копировать содержимое этой разделяемой части туда, куда указывает этот указатель.
Если вы передадите ссылку (или указатель) на локальную переменную в вызывающей функции (caller), то это будет в стековом кадре вызывающей стороны. Обратите внимание, что я не знаю ни одной архитектуры, где, если вы поднимите ковер и посмотрите, как он на самом деле работает под красивой поверхностью, ссылки на самом деле не являются указателями. Стандарт НЕ ТРЕБУЕТ этого, но именно так он реализован, по крайней мере, для большинства архитектур — мне было бы интересно понять, КАК ЕЩЕ можно его реализовать — но я не потратил много времени на обдумывание этого.
Типичное поведение функции, которая имеет struct
или же class
возвращаемый тип — это то, что он передает «дополнительный» аргумент, указывающий на временное пространство для хранения возвращаемого типа, например:
T myfunc(int x, int y)
...
void foo()
{
...
T x = myfunc(2, 18);
...
}
будет выглядеть так же, как (скрытый аргумент не обязательно будет первым аргументом — но он почти наверняка будет первым или последним):
void myfunc(T& hidden, int x, int y)
void foo()
{
...
T x;
myfunc(x, 2, 18);
...
}
Это не совсем то, что стековый фрейм является общим, так же как «мы передаем указатели, которые находятся в стековом фрейме того или иного, более раннего, вызывающего объекта.
Так что, да, наверняка возможны обращения от текущего вызываемого абонента к более раннему стековому фрейму вызывающих.
Других решений пока нет …