На самом деле это довольно интересный вопрос.
Прежде всего, обратите внимание, что мы находимся на императивном языке, означающем, что когда вы запрашиваете что-то (даже бесполезное, например, создание неиспользуемого объекта), тогда компиляторнужно соблюдать, если он не может придумать эквивалентную форму.По сути, он может исключить параметр, если докажет, что это не изменит смысла программы.
Когда вы пишете вызов функции, могут произойти две вещи (в конце):
- либо он встроен
- , либо
call
фактически выдан
Если это inlined , то параметр не передается, чтофактически означает, что неиспользуемые объекты могут быть удалены (и даже не построены), если компилятор может доказать, что задействованные конструкторы и деструкторы не выполняют какой-либо значительной работы.Это хорошо работает для структур тегов.
Когда выполняется вызов, он отправляется с определенным соглашением о вызовах.Каждый компилятор имеет свой собственный набор соглашений о вызовах, которые определяют, как передавать различные аргументы (указатель this
и т. Д.), Обычно пытаясь использовать в своих интересах доступные регистры.
Поскольку только объявлениефункция используется для определения соглашения о вызовах (отдельная модель компиляции), тогда необходимо фактически передать объект ...
Однако, если мы говорим о пустой структуре, без метода и без состояниятогда это просто неинициализированная память.Это не должно стоить дорого, но требует стекового пространства (по крайней мере, резервируя его).
Демонстрация с использованием попытки llvm:
struct tag {};
inline int useless(int i, tag) { return i; }
void use(tag);
int main() {
use(tag());
return useless(0, tag());
}
Дает:
%struct.tag = type <{ i8 }>
define i32 @main() {
entry:
; allocate space on the stack for `tag`
%0 = alloca %struct.tag, align 8 ; <%struct.tag*> [#uses=2]
; get %0 address
%1 = getelementptr inbounds %struct.tag* %0, i64 0, i32 0 ; <i8*> [#uses=1]
; 0 initialize the space used for %0
store i8 0, i8* %1, align 8
; call the use function and pass %0 by value
call void @_Z3use3tag(%struct.tag* byval %0)
ret i32 0
}
declare void @_Z3use3tag(%struct.tag* byval)
Примечание:
- , как был удален вызов
useless
, и для него не создан аргумент - , как вызвать
use
, удалить нельзя, и поэтому пробелвыделен для временного (надеюсь, что новые версии не инициализируют память 0)