Realmente es una pregunta interesante.
Antes que nada, tenga en cuenta que estamos en un lenguaje imperativo, lo que significa que cuando pide algo (incluso inútil, como construir un objeto sin usar) el compilador debe cumplir a menos que se le ocurra una forma equivalente . Básicamente, podría eludir el parámetro si pudiera demostrar que hacerlo no cambiaría el significado del programa.
Cuando se escribe una llamada a la función, pueden ocurrir dos cosas (al final):
- ya sea que se colocarán en línea
- o una
call
es en realidad emitida
Si es en línea, entonces no se pasa ningún parámetro, lo que significa que los objetos no utilizados se pueden eliminar (y ni siquiera crear) si el compilador puede demostrar que los constructores y destructores implicados no realizan ningún significado t trabajo. Funciona bien para las estructuras de etiquetas.
Cuando se emite una llamada, se emite con una convención de llamada específica. Cada compilador tiene su propio conjunto de convenciones de llamadas que especifican cómo pasar los diversos argumentos (puntero this
, etc.), generalmente tratando de aprovechar los registros disponibles.
Dado que sólo se utiliza la declaración de la función para determinar la convención de llamada (modelo de compilación independiente), entonces es necesario para realmente pasar el objeto ...
Sin embargo, si estamos hablando de una estructura vacía , sin método y sin estado, entonces esto es solo una memoria no inicializada. No debería costar mucho, pero requiere espacio en la pila (al menos, reservándolo).
demostración utilizando la prueba de audición llvm:
struct tag {};
inline int useless(int i, tag) { return i; }
void use(tag);
int main() {
use(tag());
return useless(0, tag());
}
Da:
%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)
Nota:
- cómo se eliminó la llamada a
useless
, y ningún argumento está construido para ello
- cómo llamar a
use
no puede ser eliminado, y por lo tanto el espacio se asigna para el temporal (espero que las nuevas versiones no 0-initialize la memoria)
Los resultados variarán según los compiladores y los niveles de optimización. Tendrás que probarlo. –
Tengo 10 preguntas como esta al día, si experimenté en todo lo que no haría ningún trabajo;), califico la pregunta con los dos compiladores que me interesan. –
@Hassan: Creo que han terminado antes de escribir una prueba simple en lugar de escribir toda la pregunta :) –