c++ - para - meta tags importantes
¿Cuándo debo escribir la palabra clave ''en línea'' para una función/método? (12)
¿Cuándo no debo escribir la palabra clave ''en línea'' para una función / método en C ++?
Si la función está definida en el archivo .cpp
, no debe escribir la palabra clave.
¿Cuándo no sabrá el compilador cuándo hacer una función / método ''en línea''?
No hay tal situación. El compilador no puede hacer una función en línea. Todo lo que puede hacer es incluir algunas o todas las llamadas a la función. No puede hacerlo si no tiene el código de la función (en ese caso, el vinculador debe hacerlo si puede hacerlo).
¿Importa si una aplicación es multiproceso cuando se escribe ''en línea'' para una función / método?
No, eso no importa en absoluto.
¿Cuándo debo escribir la palabra clave en inline
para una función / método en C ++?
Después de ver algunas respuestas, algunas preguntas relacionadas:
¿Cuándo no debo escribir la palabra clave ''en línea'' para una función / método en C ++?
¿Cuándo no sabrá el compilador cuándo hacer una función / método ''en línea''?
¿Importa si una aplicación es multiproceso cuando se escribe ''en línea'' para una función / método?
gcc de forma predeterminada no integra ninguna función al compilar sin la optimización habilitada. No sé sobre visual studio - deft_code
Revisé esto para Visual Studio 9 (15.00.30729.01) compilando con / FAcs y mirando el código de ensamblaje: El compilador produjo llamadas a funciones miembro sin optimización habilitada en el modo de depuración . Incluso si la función está marcada con __forceinline , no se produce ningún código de tiempo de ejecución en línea.
1) Hoy en día, casi nunca. Si es una buena idea integrar una función, el compilador lo hará sin su ayuda.
2) Siempre. Vea el # 1.
(Editado para reflejar que dividiste tu pregunta en dos preguntas ...)
A menos que esté escribiendo una biblioteca o tenga razones especiales, puede olvidarse de la inline
y utilizar la optimización de tiempo de enlace en su lugar. Elimina el requisito de que la definición de una función debe estar en un encabezado para que se considere su inclusión en las unidades de compilación, que es precisamente lo que permite inline
.
(Pero vea ¿Hay alguna razón para no usar la optimización de tiempo de enlace? )
Aún necesita integrar explícitamente su función cuando realice la especialización de plantillas (si la especialización está en el archivo .h)
Al desarrollar y depurar código, déjelo en inline
. Se complica la depuración.
La razón principal para agregarlos es ayudar a optimizar el código generado. Normalmente, este comercio incrementa el espacio de código para la velocidad, pero a veces en inline
ahorra espacio de código y tiempo de ejecución.
Pasar este tipo de pensamiento sobre la optimización del rendimiento antes de completar el algoritmo es una optimización prematura .
Cuando uno debe en línea:
1. Cuando uno quiere evitar la sobrecarga de cosas que suceden cuando la función se denomina paso de parámetros, transferencia de control, retorno de control, etc.
2. La función debe ser pequeña, con frecuencia llamada y hacer en línea es realmente ventajoso, ya que según la regla 80-20, intente hacer que la función en línea tenga un impacto importante en el rendimiento del programa.
Como sabemos, en línea es solo una solicitud de compilación similar a la del registro y le costará el tamaño del código del Objeto.
Desea ponerlo en el principio, antes de devolver el tipo. Pero la mayoría de los compiladores lo ignoran. Si está definido y tiene un bloque de código más pequeño, la mayoría de los compiladores lo consideran en línea de todos modos.
En realidad, casi nunca. Todo lo que está haciendo es sugerir que el compilador realice una función dada en línea (por ejemplo, reemplace todas las llamadas a esta función / w su cuerpo). No hay garantías, por supuesto: el compilador puede ignorar la directiva.
El compilador generalmente hará un buen trabajo de detección y optimización de cosas como esta.
Me gustaría contribuir a todas las grandes respuestas en este hilo con un ejemplo convincente para dispersar cualquier malentendido restante.
Dados dos archivos de origen, tales como:
inline111.cpp:
#include <iostream> void bar(); inline int fun() { return 111; } int main() { std::cout << "inline111: fun() = " << fun() << ", &fun = " << (void*) &fun; bar(); }
inline222.cpp:
#include <iostream> inline int fun() { return 222; } void bar() { std::cout << "inline222: fun() = " << fun() << ", &fun = " << (void*) &fun; }
Caso A:
Compilar
g++ -std=c++11 inline111.cpp inline222.cpp
Salida :
inline111: fun() = 111, &fun = 0x4029a0 inline222: fun() = 111, &fun = 0x4029a0
Discusión :
Incluso si debería tener definiciones idénticas de sus funciones en línea, el compilador de C ++ no lo marca si ese no es el caso (en realidad, debido a la compilación por separado, no hay formas de verificarlo). ¡Es tu propio deber asegurar esto!
El enlazador no se queja de la Regla de una definición , ya que
fun()
se declara como eninline
. Sin embargo, dado que inline111.cpp es la primera unidad de traducción (que en realidad llamafun()
) procesada por el compilador, el compilador creafun()
instancia defun()
en su primer encuentro de llamadas en inline111.cpp . Si el compilador decide no expandirfun()
tras su llamada desde cualquier otro lugar de su programa ( por ejemplo, desde inline222.cpp ), la llamada afun()
siempre estará vinculada a su instancia producida desde inline111.cpp (la llamada afun()
dentro de inline222.cpp también puede producir una instancia en esa unidad de traducción, pero permanecerá sin enlazar). De hecho, eso es evidente a partir de las impresiones idénticas&fun = 0x4029a0
.Finalmente, a pesar de la sugerencia en
inline
al compilador para expandir lafun()
una sola líneafun()
, ignora su sugerencia por completo, lo cual es claro porquefun() = 111
en ambas líneas.
Caso B:
Compilar (notar orden inversa) :
g++ -std=c++11 inline222.cpp inline111.cpp
Salida :
inline111: fun() = 222, &fun = 0x402980 inline222: fun() = 222, &fun = 0x402980
Discusión :
Este caso afirma lo que se ha discutido en el caso A.
Observe un punto importante, que si comenta la llamada real a
fun()
en inline222.cpp ( por ejemplo, comentecout
-statement in inline222.cpp completamente) entonces, a pesar del orden de compilación de sus unidades de traducción,fun()
será se crea una instancia de su primer encuentro de llamadas en inline111.cpp , lo que da como resultado la impresión del Caso B comoinline111: fun() = 111, &fun = 0x402980
.
Caso C:
Compilar (aviso -O2) :
g++ -std=c++11 -O2 inline222.cpp inline111.cpp
o
g++ -std=c++11 -O2 inline111.cpp inline222.cpp
Salida :
inline111: fun() = 111, &fun = 0x402900 inline222: fun() = 222, &fun = 0x402900
Discusión :
- Como se describe aquí , la optimización de
-O2
anima al compilador a expandir realmente las funciones que pueden integrarse (-fno-inline
también que-fno-inline
es la opción predeterminada sin opciones de optimización). Como es evidente por la impresión aquí, lafun()
se ha expandido en línea (de acuerdo con su definición en esa unidad de traducción en particular ), dando como resultado dos impresiones diferentes de lafun()
. A pesar de esto, todavía hay una sola instancia defun()
(como lo exige el estándar), como se desprende de la impresión idéntica&fun
.
- Como se describe aquí , la optimización de
Oh hombre, una de mis manitas.
inline
es más como static
o extern
que una directiva que le dice al compilador que enlista sus funciones. extern
, static
, inline
son directivas de vinculación, utilizadas casi exclusivamente por el vinculador, no por el compilador.
Se dice que las sugerencias en inline
para el compilador creen que la función debería estar en línea. Eso pudo haber sido cierto en 1998, pero una década más tarde el compilador no necesita tales sugerencias. Sin mencionar que los humanos usualmente están equivocados cuando se trata de optimizar el código, por lo que la mayoría de los compiladores ignoran la "pista".
static
: el nombre de la variable / función no se puede utilizar en otras unidades de traducción. El enlazador debe asegurarse de que no use accidentalmente una variable / función estáticamente definida de otra unidad de traducción.extern
: use este nombre de variable / función en esta unidad de traducción, pero no se queje si no está definido. El enlazador lo ordenará y se asegurará de que todo el código que intentó usar algún símbolo externo tenga su dirección.inline
: esta función se definirá en varias unidades de traducción, no se preocupe por ello. El enlazador debe asegurarse de que todas las unidades de traducción usen una sola instancia de la variable / función.
Nota: Generalmente, declarar las plantillas en inline
tiene sentido, ya que tienen la semántica de vinculación de en inline
ya. Sin embargo, explicit
especialización explicit
y la creación de instancias de plantillas requieren el uso en inline
.
Respuestas específicas a sus preguntas:
¿Cuándo debo escribir la palabra clave ''en línea'' para una función / método en C ++?
Solo cuando desea que la función se defina en un encabezado. Más exactamente solo cuando la definición de la función puede aparecer en varias unidades de traducción. Es una buena idea definir funciones pequeñas (como en un trazador de líneas) en el archivo de encabezado, ya que le da al compilador más información para trabajar mientras optimiza su código. También aumenta el tiempo de compilación.
¿Cuándo no debo escribir la palabra clave ''en línea'' para una función / método en C ++?
No agregue en línea solo porque cree que su código se ejecutará más rápido si el compilador lo alinea.
¿Cuándo no sabrá el compilador cuándo hacer una función / método ''en línea''?
Generalmente, el compilador podrá hacer esto mejor que tú. Sin embargo, el compilador no tiene la opción de código en línea si no tiene la definición de la función. En el código optimizado al máximo, generalmente todos
private
métodosprivate
están en línea, ya sea que lo solicite o no.Como un aparte para evitar la inclusión en GCC, use
__attribute__(( noinline ))
, y en Visual Studio, use__declspec(noinline)
.¿Importa si una aplicación es multiproceso cuando se escribe ''en línea'' para una función / método?
El subprocesamiento múltiple no afecta de ninguna manera la alineación.
- ¿Cuándo no sabrá el compilador cuándo hacer una función / método ''en línea''?
Esto depende del compilador utilizado. No confíe ciegamente en que los compiladores de hoy en día saben más que los humanos cómo hacerlo en línea y nunca deben usarlo por razones de rendimiento, porque es una directiva de vinculación en lugar de una sugerencia de optimización. Si bien estoy de acuerdo en que ideológicamente estos argumentos son correctos, encontrar la realidad podría ser una cosa diferente.
Después de leer varios subprocesos, probé por curiosidad los efectos de la línea en el código en el que estoy trabajando y los resultados fueron que obtuve una aceleración mensurable para GCC y ninguna velocidad para el compilador de Intel.
(Más detalles: simulaciones matemáticas con pocas funciones críticas definidas fuera de la clase, GCC 4.6.3 (g ++ -O3), ICC 13.1.0 (icpc -O3); agregar en línea a los puntos críticos causados + 6% de aceleración con el código GCC).
Entonces, si califica a GCC 4.6 como un compilador moderno, el resultado es que la directiva en línea sigue siendo importante si escribe tareas intensivas de CPU y sabe dónde está exactamente el cuello de botella.