Cuándo usar la función en línea y cuándo no usarla?

Sé que en línea es una pista o una solicitud al comstackdor y se usa para evitar los gastos generales de las llamadas a funciones.

Entonces, ¿sobre qué base se puede determinar si una función es candidata o no? ¿En ese caso uno debe evitar la inflación?

Evitar el costo de una llamada de función es solo la mitad de la historia.

hacer:

  • use en inline lugar de #define
  • las funciones muy pequeñas son buenas candidatas para inline : código más rápido y ejecutables más pequeños (más posibilidades de permanecer en el caché del código)
  • la función es pequeña y se llama muy a menudo

no hacer:

  • funciones grandes: conduce a archivos ejecutables más grandes, lo que afecta significativamente el rendimiento, independientemente de la ejecución más rápida que resulta de la sobrecarga de llamadas
  • funciones en línea que están vinculadas a E / S
  • la función rara vez se usa
  • constructores y destructores: incluso cuando están vacíos, el comstackdor genera código para ellos
  • rompiendo la compatibilidad binaria al desarrollar bibliotecas:
    • en línea una función existente
    • cambiar una función en línea o hacer una función en línea no en línea: la versión anterior de la biblioteca llama a la implementación anterior

Al desarrollar una biblioteca, para hacer que una clase sea extensible en el futuro, debes:

  • agregar destructor virtual no en línea, incluso si el cuerpo está vacío
  • hacer que todos los constructores no estén en línea
  • escribir implementaciones no en línea del constructor de copias y el operador de asignación, a menos que la clase no se pueda copiar por valor

Recuerde que la palabra clave en inline es una pista para el comstackdor: el comstackdor puede decidir no alinear una función y, en primer lugar, puede decidir alinear las funciones que no estaban marcadas en inline . Generalmente evito marcar la función en inline (aparte tal vez cuando escribo funciones muy, muy pequeñas).

En cuanto al rendimiento, el enfoque inteligente es (como siempre) perfilar la aplicación, y luego inline un conjunto de funciones que representan un cuello de botella.

Referencias

  • En línea o no en línea
  • [9] Funciones en línea
  • Políticas / problemas de compatibilidad binaria con C ++
  • GotW # 33: en línea
  • Inline Redux
  • C ++ efectivo – Elemento 33: Use la alineación juiciosamente

EDITAR: Bjarne Stroustrup, el lenguaje de progtwigción C ++:

Una función se puede definir para estar en inline . Por ejemplo:

 inline int fac(int n) { return (n < 2) ? 1 : n * fac(n-1); } 

El especificador en inline es una sugerencia para el comstackdor de que debe intentar generar código para una llamada de fac() línea en lugar de establecer el código para la función una vez y luego llamar a través del mecanismo de llamada de función habitual. Un comstackdor inteligente puede generar la constante 720 para un fac(6) llamada fac(6) . La posibilidad de funciones en línea mutuamente recursivas, funciones en línea que se repiten o no dependiendo de la entrada, etc., hace que sea imposible garantizar que cada llamada de una función en inline esté realmente en línea. El grado de inteligencia de un comstackdor no puede legislarse, por lo que un comstackdor puede generar 720 , otro 6 * fac(5) y otro más un fac(6) llamada no en línea fac(6) .

Para hacer posible la alineación en ausencia de recursos de comstackción y enlace inusualmente inteligentes, la definición (y no solo la statement) de una función en línea debe estar dentro del scope (§9.2). Un especificador en inline no afecta la semántica de una función. En particular, una función en línea aún tiene una dirección única y también tiene variables static (§7.1.2) de una función en línea.

EDIT2: ISO-IEC 14882-1998, 7.1.2 Especificadores de funciones

Una statement de función (8.3.5, 9.3, 11.4) con un especificador en inline declara una función en línea. El especificador en línea indica a la implementación que la sustitución en línea del cuerpo de la función en el punto de llamada es preferible al mecanismo de llamada de función habitual. No se requiere una implementación para realizar esta sustitución en línea en el punto de llamada; sin embargo, incluso si esta sustitución en línea se omite, las otras reglas para las funciones en línea definidas en 7.1.2 se seguirán respetando.

inline tiene muy poco que ver con la optimización. inline es una instrucción para que el comstackdor no produzca un error si la definición dada de la función ocurre varias veces en el progtwig y una promesa de que la definición ocurrirá en cada traducción que se use y donde quiera que aparezca tendrá exactamente la misma definición .

Dadas las reglas anteriores, inline es adecuado para funciones cortas cuyo cuerpo no necesita incluir dependencias adicionales sobre lo que solo una statement necesitaría. Cada vez que se encuentra la definición, se debe analizar y se puede generar un código para su cuerpo, por lo que implica una sobrecarga del comstackdor sobre una función definida solo una vez en un único archivo fuente.

Un comstackdor puede alinear (es decir, reemplazar una llamada a la función con código que realiza esa acción de esa función) cualquier llamada de función que elija. Solía ​​ocurrir que “obviamente” no podía alinear una función que no estaba declarada en la misma unidad de traducción que la llamada, pero con el uso creciente de la optimización de tiempo de enlace, incluso ahora esto no es cierto. Igualmente cierto es el hecho de que las funciones marcadas en inline pueden no estar en línea.

Decir al comstackdor que debe alinear una función es una optimización, y la regla de optimización más importante es que la optimización prematura es la raíz de todo mal. Siempre escriba un código claro (usando algoritmos eficientes), luego perfile su progtwig y solo optimice las funciones que llevan demasiado tiempo.

Si encuentra que una función en particular es muy corta y simple, y se llama decenas de miles de veces en un circuito interno cerrado, podría ser un buen candidato.

Sin embargo, es posible que se sorprenda: muchos comstackdores C ++ le agregarán pequeñas funciones automáticamente, y es posible que también ignoren su solicitud de alineación.

¡La optimización temprana es la raíz de todo mal!

Como regla general, usualmente alineo solo “getters” y “setters”. Una vez que el código está funcionando y es estable, los perfiles pueden mostrar qué funciones podrían beneficiarse de la creación.

Por otro lado, la mayoría de los comstackdores modernos tienen algoritmos de optimización bastante buenos y detallarán lo que debería haber escrito para usted.

Reasumiendo: escriba funciones en línea de una sola línea y preocúpese por otras más adelante.

La mejor manera de averiguarlo es perfilar su progtwig y marcar pequeñas funciones que se llaman muchas veces y quemar a través de ciclos de CPU como en inline . La palabra clave aquí es “pequeña”: una vez que la sobrecarga de la llamada a la función es insignificante en comparación con el tiempo empleado en la función, no tiene sentido encuadrarla.

El otro uso que sugeriría es que si tiene funciones pequeñas que son llamadas en el código de rendimiento crítico con la frecuencia suficiente para hacer que una memoria caché se pierda, también debería incluirlas. Nuevamente, es algo que el perfilador debería poder decirle.

Las funciones en línea pueden mejorar el rendimiento de su código al eliminar la necesidad de insertar argumentos en la stack. si la función en cuestión se encuentra en una parte crítica de su código, debe tomar la decisión en línea no en línea en la parte de optimización de su proyecto,

puede leer más sobre las líneas en el faq c ++

A menudo uso las funciones en línea no como una optimización, sino para hacer que el código sea más legible. A veces, el código en sí es más corto y más fácil de entender que los comentarios, nombres descriptivos, etc. Por ejemplo:

 void IncreaseCount() { freeInstancesCnt++; } 

El lector conoce inmediatamente la semántica completa del código.

Generalmente sigo una regla de pulgar donde hago una función con 3-4 declaraciones simples como en línea. Pero es bueno recordar que es solo una pista para el comstackdor. La última llamada para hacerla en línea o no es tomada solo por el comstackdor. Si hay más de estas muchas afirmaciones que no declararé en línea como con un comstackdor estúpido, esto puede llevar a la saturación del código.

La mejor manera sería examinar y comparar las instrucciones generadas para inline y no inlined. Sin embargo, siempre es seguro omitir en inline . Usar en inline podría ocasionar problemas que no desea.

Al decidir si usar en línea, generalmente tengo en cuenta la siguiente idea: en las máquinas modernas, la latencia de la memoria puede ser un cuello de botella más grande que los cálculos en bruto. Se sabe que las funciones de entrada que se llaman a menudo aumentan el tamaño del ejecutable. Además, dicha función podría almacenarse en la memoria caché de códigos de la CPU, lo que reducirá el número de fallas de la memoria caché cuando se necesite acceder a ese código.

Por lo tanto, tiene que decidir por sí mismo: ¿aumenta o disminuye el tamaño del código de máquina generado? ¿Qué tan probable es que llamar a la función causará una falta de caché? Si está salpicado en todo el código, entonces diría que la probabilidad es alta. Si está restringido a un solo ciclo cerrado, entonces la probabilidad es, con suerte, baja.

Por lo general, uso en línea en los casos que menciono a continuación. Sin embargo, cuando esté genuinamente preocupado por el rendimiento, la creación de perfiles es esencial. Además, es posible que desee comprobar si el comstackdor realmente toma la pista.

  • Rutinas cortas que se llaman en un ciclo cerrado.
  • Accesores muy básicos (get / set) y funciones de envoltura.
  • El código de plantilla en los archivos de encabezado desafortunadamente obtiene automáticamente la sugerencia en línea.
  • Código corto que se usa como una macro. (Por ejemplo, min () / max ())
  • Rutinas de matemáticas cortas.

Además, un método en línea tiene efectos secundarios graves cuando se mantienen proyectos grandes. Cuando se cambia el código en línea, el comstackdor reconstruirá automáticamente todos los archivos que lo utilizan (es un buen comstackdor). Esto podría perder mucho tiempo de desarrollo.

Cuando un método en inline se transfiere a un archivo fuente y ya no está en línea, se debe reconstruir todo el proyecto (al menos esta ha sido mi experiencia). Y también cuando los métodos se convierten en línea.

Se debe usar el calificador de función en línea solo cuando el código de función es pequeño. Si las funciones son más grandes, se deben preferir las funciones normales, ya que el ahorro en espacio de memoria vale la pena el pequeño sacrificio en velocidad de ejecución.

He leído algunas respuestas y veo que faltan algunas cosas.

La regla que uso no es para usar en línea, a menos que quiera que esté en línea. Parece tonto, ahora explicación.

Los comstackdores son lo suficientemente inteligentes y las funciones cortas siempre lo hacen en línea. Y nunca funciona tanto como en línea, a menos que el progtwigdor diga que haga eso.

Sé que en línea es una pista o solicitud al comstackdor

En realidad, en inline es una orden para el comstackdor, no tiene opciones y después inline palabra clave en inline hace que todo el código esté en línea. Por lo tanto, nunca puede usar la palabra clave en inline y el comstackdor diseñará el código más corto.

Entonces, ¿cuándo usar en inline ?

Para usar si quieres tener algún código en línea. Solo conozco un ejemplo, porque lo uso en una sola situación. Es autenticación de usuario.

Por ejemplo, tengo esta función:

 inline bool ValidUser(const std::string& username, const std::string& password) { //here it is quite long function } 

No importa cuán grande sea esta función, quiero tenerlo como en línea porque hace que mi software sea más difícil de descifrar.