¿Cuándo debería escribir la palabra clave ‘en línea’ para una función / método?

¿Cuándo debería 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 debería escribir la palabra clave ‘inline’ para una función / método en C ++?

  • ¿Cuándo el comstackdor no sabrá 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?

Oh hombre, uno de mis manoseos.

inline es más parecido a static o extern que una directiva que le dice al comstackdor que alinee sus funciones. extern , static , inline son directivas de vinculación, usadas casi exclusivamente por el enlazador, no por el comstackdor.

Se dice que los consejos en inline para el comstackdor creen que la función debe estar en línea. Eso puede haber sido cierto en 1998, pero una década después el comstackdor no necesita tales pistas. 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 comstackdores ignoran la ‘pista’.

  • static : el nombre de variable / función no se puede usar en otras unidades de traducción. El enlazador necesita 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 resolverá 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. El vinculador debe asegurarse de que todas las unidades de traducción utilicen una única instancia de la variable / función.

Nota: Generalmente, declarar plantillas en inline tiene sentido, ya que ya tienen la semántica de vinculación de en inline . Sin embargo, explicit especialización explicit y la creación de instancias de las plantillas requieren ser utilizadas en línea.


Respuestas específicas a sus preguntas:

  • ¿Cuándo debería escribir la palabra clave ‘inline’ para una función / método en C ++?

    Solo cuando desee que la función se defina en un encabezado. Más exactamente solo cuando la definición de la función puede aparecer en múltiples unidades de traducción. Es una buena idea definir funciones pequeñas (como en un liner) en el archivo de encabezado, ya que le da al comstackdor más información para trabajar mientras optimiza su código. También aumenta el tiempo de comstackción.

  • ¿Cuándo no debería escribir la palabra clave ‘inline’ para una función / método en C ++?

    No agregue en línea solo porque crea que su código se ejecutará más rápido si el comstackdor lo inscribe.

  • ¿Cuándo el comstackdor no sabrá cuándo hacer una función / método ‘en línea’?

    Generalmente, el comstackdor podrá hacer esto mejor que usted. Sin embargo, el comstackdor no tiene la opción de codificar en línea si no tiene la definición de función. En el código optimizado al máximo, generalmente todos private métodos private están en línea, ya sea que lo solicite o no.

    Como un aparte para evitar la alineació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 la alineación de ninguna manera.

Me gustaría contribuir a todas las grandes respuestas en este hilo con un ejemplo convincente para dispersar cualquier malentendido restante.

Dado dos archivos fuente, como:

  • inline111.cpp:

     #include  void bar(); inline int fun() { return 111; } int main() { std::cout << "inline111: fun() = " << fun() << ", &fun = " << (void*) &fun; bar(); } 
  • inline222.cpp:

     #include  inline int fun() { return 222; } void bar() { std::cout << "inline222: fun() = " << fun() << ", &fun = " << (void*) &fun; } 

  • Caso A:

    Comstackr :

     g++ -std=c++11 inline111.cpp inline222.cpp 

    Salida :

     inline111: fun() = 111, &fun = 0x4029a0 inline222: fun() = 111, &fun = 0x4029a0 

    Discusión :

    1. Aunque debería tener definiciones idénticas de sus funciones en línea, el comstackdor de C ++ no lo marca si ese no es el caso (en realidad, debido a la comstackción por separado no tiene forma de verificarlo). ¡Es su propio deber asegurar esto!

    2. Linker no se queja de One Definition Rule , ya que fun() se declara en inline . Sin embargo, como inline111.cpp es la primera unidad de traducción (que en realidad llama a fun() ) procesada por el comstackdor, el comstackdor crea fun() instancia de fun() en su primer encuentro de llamada en inline111.cpp . Si el comstackdor decide no expandir fun() a su llamada desde cualquier otro lugar en su progtwig ( por ejemplo, desde inline222.cpp ), la llamada a fun() siempre estará vinculada a su instancia producida desde inline111.cpp (la llamada a la fun() inside inline222.cpp también puede producir una instancia en esa unidad de traducción, pero permanecerá desvinculada). De hecho, eso es evidente a partir de las impresiones idénticas &fun = 0x4029a0 .

    3. Finalmente, a pesar de la sugerencia en inline para que el comstackdor expanda realmente la fun() una sola línea fun() , ignora por completo su sugerencia, lo cual es claro porque fun() = 111 en ambas líneas.


  • Caso B:

    Comstackr (observar el orden inverso) :

     g++ -std=c++11 inline222.cpp inline111.cpp 

    Salida :

     inline111: fun() = 222, &fun = 0x402980 inline222: fun() = 222, &fun = 0x402980 

    Discusión :

    1. Este caso afirma lo que se discutió en el Caso A.

    2. Observe un punto importante, que si comenta la llamada real a fun() en inline222.cpp ( por ejemplo, comenta la frase cout -en inline222.cpp por completo), a pesar del orden de comstackción de sus unidades de traducción, fun() será instanciado en su primer encuentro de llamada en inline111.cpp , resultando en una impresión para el Caso B como en inline111: fun() = 111, &fun = 0x402980 .


  • Caso C:

    Comstackr (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 :

    1. Como se describe aquí , la optimización de -O2 alienta al comstackdor a expandir realmente las funciones que se pueden incluir ( -fno-inline cuenta también que -fno-inline es el predeterminado sin opciones de optimización). Como es evidente a partir de la descripción aquí, el fun() se ha expandido en línea (de acuerdo con su definición en esa unidad de traducción particular ), lo que resulta en dos impresiones fun() diferentes fun() . A pesar de esto, solo hay una instancia de fun() enlazada globalmente (tal como lo exige el estándar), como es evidente en una impresión idéntica &fun .

Aún necesita especificar explícitamente su función al hacer la especialización de la plantilla (si la especialización está en el archivo .h)

1) Hoy en día, casi nunca. Si es una buena idea alinear una función, el comstackdor lo hará sin su ayuda.

2) Siempre. Ver # 1.

(Editado para reflejar que dividiste tu pregunta en dos preguntas …)

¿Cuándo no debería escribir la palabra clave ‘inline’ 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 el comstackdor no sabrá cuándo hacer una función / método ‘en línea’?

No hay tal situación El comstackdor no puede hacer una función en línea. Todo lo que puede hacer es alinear 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 enlazador debe hacerlo si es capaz de 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.

En realidad, casi nunca. Todo lo que está haciendo es sugerir que el comstackdor realice una función determinada en línea (por ejemplo, reemplace todas las llamadas a esta función / w su cuerpo). No hay garantías, por supuesto: el comstackdor puede ignorar la directiva.

El comstackdor generalmente hará un buen trabajo detectando + optimizando cosas como esta.

  • ¿Cuándo el comstackdor no sabrá cuándo hacer una función / método ‘en línea’?

Esto depende del comstackdor utilizado. No confíe ciegamente en que los comstackdores de hoy en día saben mejor que los humanos cómo 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, el encuentro con la realidad podría ser algo diferente.

Después de leer varios hilos, intenté por curiosidad los efectos del código en línea que estoy trabajando y los resultados fueron que obtuve una aceleración mensurable para GCC y no hubo aceleración para el comstackdor de Intel.

(Más detalles: simulaciones matemáticas con algunas funciones críticas definidas fuera de 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 GCC 4.6 como un comstackdor moderno, el resultado es que la directiva en línea aún importa si usted escribe tareas intensivas de CPU y sabe dónde está exactamente el cuello de botella.

gcc de forma predeterminada no incorpora ninguna función al comstackr sin la optimización habilitada. No sé sobre visual studio – deft_code

Comprobé esto para Visual Studio 9 (15.00.30729.01) comstackndo con / FAcs y mirando el código ensamblador: el comstackdor produjo llamadas a funciones miembro sin la 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.

Desea ponerlo desde el principio, antes del tipo de devolución. Pero la mayoría de los comstackdores lo ignoran. Si está definido, y tiene un bloque de código más pequeño, la mayoría de los comstackdores lo consideran en línea de todos modos.

Al desarrollar y depurar código, deje en inline . Esto complica la depuración.

La razón principal para agregarlos es ayudar a optimizar el código generado. Por lo general, esto incrementa el espacio de código para la velocidad, pero a veces en inline guarda el espacio del código y el tiempo de ejecución.

Gastar este tipo de pensamiento sobre la optimización del rendimiento antes de la finalización del algoritmo es una optimización prematura .

Cuando uno debe en línea:

1. Cuando uno quiere evitar la sobrecarga de cosas que suceden cuando se llama a la función como pasar parámetros, controlar la transferencia, controlar el retorno, etc.

2. La función debe ser pequeña, frecuentemente llamada y hacer en línea es realmente ventajoso ya que según la regla 80-20, intente hacer que esas funciones en línea tengan un gran impacto en el rendimiento del progtwig.

Como sabemos que inline es solo una solicitud al comstackdor similar al registro y le costará en el tamaño del código Object.

A menos que esté escribiendo una biblioteca o tenga motivos especiales, en su lugar puede olvidarse de la optimización en tiempo de enlace y en línea. Elimina el requisito de que una definición de función debe estar en un encabezado para que se considere su inclusión en las unidades de comstackción, que es precisamente lo que permite en inline .

(Pero mira ¿Hay alguna razón para no usar la optimización de tiempo de enlace? )