2008-09-13 7 views
34

Si bien sería conveniente usar funciones en línea en algunas situaciones,¿Qué hay de malo con el uso de funciones en línea?

¿Hay algún inconveniente con las funciones en línea?

Conclusión:

Al parecer, no hay nada malo con el uso de las funciones en línea.

¡Pero vale la pena señalar los siguientes puntos!

  • El uso excesivo de inline puede hacer que los programas sean más lentos. Dependiendo del tamaño de una función, al alinearla puede aumentar o disminuir el tamaño del código. Alinear una función de acceso muy pequeña generalmente disminuirá el tamaño del código, mientras que una función muy grande puede aumentar drásticamente el tamaño del código. En los procesadores modernos, el código más pequeño generalmente se ejecuta más rápido debido al mejor uso de la memoria caché de instrucciones. - Google Guidelines

  • Los beneficios de velocidad de las funciones en línea tienden a disminuir a medida que la función aumenta de tamaño. En algún momento la sobrecarga de la llamada a la función se hace pequeño en comparación con la ejecución del cuerpo de la función, y el beneficio se pierde - Source

  • Hay pocas situaciones en las que una función en línea puede no funcionar:

    • Para una función que devuelve valores; si existe una declaración de devolución.
    • Para una función que no devuelve ningún valor; si existe una instrucción loop, switch o goto.
    • Si una función es recursiva. -Source
  • La palabra clave __inline provoca una función para ser inline sólo si se especifica la opción optimizada. Si se especifica optimize, el hecho de que se cumpla o no el __inline depende de la configuración de la opción del optimizador en línea. De forma predeterminada, la opción en línea tiene efecto cada vez que se ejecuta el optimizador. Si especifica optimizar, también debe especificar la opción noinline si desea ignorar la palabra clave __inline. -Source

+1

Buen resumen. Tenga en cuenta que el compilador aplica las viñetas sobre cuándo está en línea y, cuando no, son más bien específicas del compilador. (MSVC lo hará diferente de gcc de ...) –

+0

"Hay algunas situaciones en las que una función en línea puede no funcionar: Para una función que devuelve valores; si existe una declaración de devolución. Para una función que no devuelve ningún valor "También puede decir que" las funciones en línea pueden no funcionar ". –

Respuesta

21

Vale la pena señalar que la palabra clave en línea es en realidad solo una pista para el compilador. El compilador puede ignorar el en línea y simplemente generar código para la función en algún lugar.

El inconveniente principal de las funciones en línea es que puede aumentar el tamaño de su ejecutable (dependiendo del número de instancias). Esto puede ser un problema en algunas plataformas (por ejemplo, sistemas integrados), especialmente si la función en sí es recursiva.

También recomendaría hacer funciones en línea muy pequeño - Los beneficios de velocidad de las funciones en línea tienden a disminuir a medida que la función aumenta de tamaño.En algún punto, la sobrecarga de la llamada de función se vuelve pequeña en comparación con la ejecución del cuerpo de la función, y se pierde el beneficio.

2

I duda it. Incluso el compilador enumera automáticamente algunas funciones para la optimización.

+0

Ampliaré lo que dijo @Vaibhav, y declararé que "en línea" es el "registro" de la década de 2000. Recuerde la palabra clave "registrarse"? ¿Alguien lo ha usado desde la década de 1980? –

+0

@PaulTomblin: El estándar C establece que las unidades de traducción múltiples pueden declararse funciones "en línea" del mismo nombre, y recomienda que se plieguen en una definición común; en la mayoría de los casos, el código que usa 'inline' podría funcionar en un compilador que no lo reconoce mediante' #define inline static', pero el uso de 'inline' en un compilador que lo comprenda generalmente arrojará mejores resultados que 'estático'. – supercat

14

Podría aumentar el tamaño de la ejecutable, y no creo compiladores siempre realmente hacer ellos en línea a pesar de que utilizó la palabra clave en línea. (¿O es otro revés, como lo Vaibhav dijo? ...)

Creo que es por lo general bien si la función tiene sólo 1 o 2 declaraciones.

Editar: Esto es lo que el documento Linux CodingStyle dice al respecto:

Capítulo 15: La enfermedad línea

Parece que hay un percepción errónea de que gcc tiene una magia "hacen yo más rápido "opción de aceleración llamada " en línea ". Si bien el uso de inlines puede ser apropiado (por ejemplo, como un medio de sustitución de macros, consulte el Capítulo 12), con mucha frecuencia no lo es. uso abundante de la palabra clave en línea lleva a una forma mucho núcleo más grande, que a su vez afecta al sistema como un todo hacia abajo, debido a la huella de Icaché más grande para la CPU y simplemente porque hay menos memoria disponible para la memoria intermedia de páginas . Solo piénselo; un error de memoria de página provoca una búsqueda de disco, que fácilmente toma 5 milisegundos. Hay MUCHOS ciclos de cpu que pueden entrar en estos 5 milisegundos.

Una regla de oro razonable es no poner en línea en las funciones que tienen más que 3 líneas de código en ellas. Un excepción a esta regla son los casos donde un parámetro es conocido por ser una constante de tiempo de compilación , y como resultado de esta constantness que sabe la compilador será capaz de optimizar más de la función de su distancia en tiempo de compilación hora. Para un buen ejemplo de este caso posterior, vea la función en línea kmalloc().

A menudo las personas argumentan que la adición en línea a las funciones que son estáticos y se utilizan sólo una vez es siempre una victoria ya que no hay ninguna solución de compromiso espacio. Si bien esto es técnicamente correcto, gcc es capaz de inlining éstos automáticamente sin ayuda, y el problema de mantenimiento de la eliminación de la línea cuando un segundo usuario aparece es mayor que el valor potencial de la pista que le dice a gcc para hacer algo que habría hecho de todos modos.

+0

En VC++ aumentará el tamaño, no está seguro acerca de otros compiladores. Pero si eligieron hacerlo en línea, estoy seguro de que también lo haría más grande. –

+0

por ellos me refiero al compilador en cuestión. –

+0

Sí, el aumento de tamaño fue el más importante que escuché ... ¡curiosidad por saber si hay más! – prakash

0

inlining excesivo de funciones puede aumentar el tamaño del ejecutable compilado que puede tener un impacto negativo en el rendimiento de la caché, pero hoy en día compilador de decidir acerca función línea por su cuenta (en función de muchos criterios) e ignorar palabra inline.

1

También debe tener en cuenta que la palabra clave en línea es solo una solicitud. El compilador puede elegir no alinearlo, del mismo modo el compilador puede elegir hacer una función en línea que no definió como en línea si cree que vale la pena la compensación de velocidad/tamaño.

Esta decisión generalmente se basa en varias cosas, como la configuración entre optimizar la velocidad (evita la llamada a la función) y optimizar el tamaño (la alineación puede causar la hinchazón del código, por lo que no es ideal para grandes repetidamente utilizado funciones).

con el compilador de VC++ puede overide esta decisión mediante el uso de __forceinline

SO en general: uso en línea si realmente quiere tener una función en un encabezado, pero theres otra parte mucho sentido, porque si vas a ganar algo de eso, un buen compilador lo hará en línea para usted de todos modos.

4

Estoy de acuerdo con los otros comentarios:

  • en línea puede ser innecesario ya que el compilador lo hará
  • en línea puede hinchar su código

Un tercer punto se puede te obligan a exponer detalles de implementación en sus encabezados, .eg,

class OtherObject; 

class Object { 
public: 
    void someFunc(OtherObject& otherObj) { 
     otherObj.doIt(); // Yikes requires OtherObj declaration! 
    } 
}; 

Sin el en línea una declaración adelante de OtherObject era todo lo que necesitabas. Con el en línea su encabezado necesita la definición de OtherObject.

+0

No creo que en la práctica su primera viñeta sea correcta. El compilador puede * ignorar * en línea, pero solo tiene la opción si la definición de la función está visible en el sitio de llamadas y eso lo limita más o menos a las funciones locales de la TU actual. –

1

Incrustar funciones más grandes puede hacer que el programa sea más grande, lo que da como resultado más errores de caché y lo hace más lento.

Decidir cuándo una función es lo suficientemente pequeña como para aumentar el rendimiento es bastante complicado. Google's C++ Style Guide recomienda solo funciones de alineación de 10 líneas o menos.

4

Como han mencionado otros, la palabra clave en línea es solo una pista para el compilador. De hecho, la mayoría de los compiladores modernos ignorarán por completo esta pista. El compilador tiene su propia heurística para decidir si alinea una función y, francamente, no quiere su consejo, muchas gracias.

Si realmente, realmente quiere hacer algo en línea, si usted ha hecho que perfila y miramos el desmontaje para asegurar que anulando la heurística compilador realmente tiene sentido, entonces es posible:

  • En VC++, utilice la palabra clave __forceinline
  • en GCC, el uso __attribute __ ((always_inline))

la palabra clave en línea tiene un segundo, propósito válido sin embargo - funciones en archivos de cabecera, pero no dentro de una definición de clase declarar. La palabra clave en línea es necesaria para decirle al compilador que no genere múltiples definiciones de la función.

+0

Probablemente signifique funciones de "definición" en archivos de encabezado en lugar de declarar. –

+0

La definición debe estar disponible para que el compilador decida si alineará la función o no. Intra-TU esto requiere que las definiciones sean visibles en el archivo de encabezado, que requiere la palabra clave 'en línea'. Por lo tanto, nos lleva de vuelta al desarrollador que tiene que hacer la llamada. –

+0

"En realidad, la mayoría de los compiladores modernos ignorarán por completo esta pista". ¿Puedes respaldar esto con las fuentes? En la documentación clang, se afirma que se trata como una pista, pero ciertamente no se ignora por completo. La documentación de MSVC establece algo similar. Su declaración no es válida para dos de los compiladores "modernos" más populares. – rdb

4

Hay un problema con inline: una vez que definiste una función en un archivo de cabecera (lo que implica en línea, ya sea explícito o implícito definiendo un cuerpo de una función miembro dentro de la clase) no hay manera simple de cambiarlo sin forzar sus usuarios para recompilar (en lugar de volver a vincular). A menudo, esto causa problemas, especialmente si la función en cuestión está definida en una biblioteca y el encabezado es parte de su interfaz.

+0

Sí, este es un problema que a menudo se pierde con las funciones en línea exportadas desde una biblioteca compartida. – BeeOnRope

2

no sé si es mi respuesta a la pregunta relacionada pero:

muy cuidado con métodos virtuales en línea! Algunos compiladores erróneos (versiones anteriores de Visual C++, por ejemplo) generarían código en línea para los métodos virtuales en los que el comportamiento estándar consistía en no hacer más que bajar al árbol de herencia y llamar al método apropiado.

-1
  1. Como otras personas dijeron que función en línea puede crear un problema si el código es large.As cada instrucción se almacena en una ubicación de memoria específica, por lo que la sobrecarga de la función en línea hacen un código de tomar más tiempo para llegar excitado

  2. hay pocas otras situaciones en línea puede no funcionar

    1. no funciona en el caso de la función recursiva.
    2. Es posible que tampoco funcione con la variable estática.
    3. tampoco funciona en caso de que haya un uso de un bucle, un interruptor, etc.o podemos decir eso con múltiples instrucciones.
    4. Y la función main no puede funcionar como función en línea.
0

Entre otros problemas con las funciones en línea, lo que he visto fuertemente abusado (he visto las funciones en línea de 500 líneas), lo que tiene que tener en cuenta son:

  • acumulación inestabilidad

    • Cambio de la fuente de una función en línea hace que todos los usuarios de la cabecera de volver a compilar
    • #include s fuga en el cliente. Esto puede ser muy desagradable si retrabaja una función en línea y elimina un encabezado usado que ya no se usa y en el que se ha basado algún cliente.
  • tamaño del ejecutable

    • Cada vez que una línea se colocarán en línea en lugar de una instrucción de llamada al compilador tiene que generar todo el código de la línea. Esto está bien si el código de la función es corto (una o dos líneas), no tan bueno si la función es larga
    • Algunas funciones pueden producir mucho más código que el que aparece al principio. En mi caso, es un destructor 'trivial' de una clase que tiene muchas variables de miembros que no son pod (o dos o 3 variables de miembros con destructores algo desordenados). Se debe generar una llamada para cada destructor.
  • tiempo de ejecución

    • esto es muy dependiente de la memoria caché de la CPU y bibliotecas compartidas, pero localidad de referencia es importante. Si el código que está insertando se almacena en la caché de la CPU en un lugar, un número de clientes puede encontrar el código y no sufrir una falta de memoria caché y la consiguiente recuperación de la memoria (y peor, en caso de que ocurra, una recuperación del disco) . Lamentablemente, este es uno de esos casos en los que realmente necesita hacer un análisis de rendimiento.

El estándar de codificación donde trabajo las funciones en línea de límite para los fijadores de simples/captadores, y en concreto a decir destructores no deben estar en línea, a menos que tenga las mediciones de rendimiento para mostrar la inlining confiere una ventaja notable.

Cuestiones relacionadas