2010-03-23 15 views
18

Si definimos una función de miembro dentro de la propia definición de clase, ¿se trata necesariamente en línea o es solo una solicitud al compilador que puede ignorar?Funciones en línea en C++

+0

Consulte también http://stackoverflow.com/questions/908830/isnt-cs-inline-totally-optional/910686#910686 –

Respuesta

18

Sí, las funciones que se definen dentro de un cuerpo de clase son implícitamente inline.

(Como con otras funciones declaradas inline no significa que el compilador tiene que realizar la expansión en línea en los lugares donde se llama a la función, solo habilita las relajaciones permitidas de la "regla de una definición", combinada con el requisito que se debe incluir una definición en todas las unidades de traducción donde se usa la función.)

2

Es una solicitud al compilador que puede ignorar.

+4

No, es un requisito. Si se define una función en un cuerpo de clase, se debe tratar como si se hubiera declarado 'en línea'. –

+5

como cualquier solicitud 'en línea' que el compilador puede ignorar. – shoosh

+1

Dado que se puede ignorar, y la mayoría de los compiladores se alinearán cuando corresponda, incluso cuando no lo solicite, es una pista bastante inútil. – marr75

3

Es necesariamente tratado por el compilador como una solicitud de en línea, que puede ignorar. Hay algunos modismos para definir algunas funciones en el encabezado (por ejemplo, destructores virtuales vacíos) y algunas definiciones de encabezado necesarias (funciones de plantilla), pero aparte de eso, vea GotW #33 para obtener más información.

Algunos han notado que el compilador incluso puede alinear funciones que nunca se le pidieron, pero no estoy seguro de si eso podría frustrar el propósito de solicitar alinear una función.

+0

Depende del compilador. En general, en línea es una pista que no hace mucho. Creo que la mayoría de los compiladores dirigidos a las plataformas integradas escuchan los consejos más de cerca, y este es realmente el único espacio donde puede superar al compilador después de un diseño cuidadoso. – marr75

3

De hecho, está en línea, pero cualquier solicitud en línea puede ser ignorada por el compilador.

2

El estándar ISO C++ 2003 dice

7.1.2/2 una declaración de función (8.3.5, 9.3, 11.4) con un especificador inline declara una función en línea . El especificador en línea indica a la implementación que sustitución en línea de la función cuerpo en el punto de llamada debe ser preferido a la función habitual llamar al mecanismo
. 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 demás reglas para las funciones en línea definidas como por 7.1.2 se seguirán respetando.

7.1.2/3 Una función definida dentro de una definición de clase es una función en línea
. El especificador en línea deberá no aparecer en una declaración de la función de alcance de bloque .

7.1.2/4 una función en línea se definirá en cada unidad de traducción en
el que se utiliza y tendrá exactamente la misma definición en todos los casos
(3.2). [Nota: se puede encontrar una llamada a la función en línea
antes de que su definición aparezca en la unidad de traducción . ] Si una función con enlace externo se declara en línea en una unidad de traducción, se declarará en línea en todas las unidades de traducción en las que aparece ; no se requiere diagnóstico.Una función en línea con enlace externo tendrá la misma dirección en todas las unidades de traducción. Una variable local estática en una función extern inline
siempre se refiere al mismo objeto . Un literal de cadena en una función en línea externa
es el mismo objeto en diferentes unidades de traducción
.

+0

Esta es la respuesta más útil, pero también es engañosa; en general, los compiladores convencionales se centran en el elemento "Una implementación no es necesaria para realizar esta sustitución en línea" del estándar. – marr75

1

hay dos cosas que no deben ser agrupados:

  1. Cómo marcar una función como línea: definirlo con línea frente a la firma o definirlo en el punto de declaración;
  2. Lo que el compilador tratará con este marcado en línea: independientemente de cómo haya marcado la función como en línea, se tratará como una solicitud del compilador.
4

Según lo manifestado por otros, un método definido dentro de una clase se solicita automáticamente en línea. Es útil entender por qué.

Supongamos que no lo fueran. Tendría que generar código para dicha función, y en todas partes se llama, una instrucción de salto a subrutina tendría que hacer referencia a la ubicación, a través del enlazador.

class A { 
public: 
    void f() { ... your code ... } 
}; 

Cada vez que este código se ve, si no es en línea, el compilador sólo puede asumir que se debe generar, por lo que generaría un símbolo. Supongamos que era así:

A__f_v:

Si ese símbolo era global, entonces si pasó a incluir el código de clase varias veces en diferentes módulos, que tendría un error de símbolos se multiplican definido en tiempo de enlace. Entonces no puede ser global. En cambio, es un archivo local.

Imagine que incluye el archivo de encabezado anterior en una serie de módulos. En cada uno, generará una copia local de ese código. Lo cual es mejor que no compilar en absoluto, pero obtendrás varias copias del código cuando realmente solo necesites uno.

Esto lleva a la siguiente conclusión: si su compilador no va a alinear una función, es mucho mejor declararla en algún lugar una vez y no solicitar que esté en línea.

Lamentablemente, lo que es y no es en línea no es portátil. Está definido por el escritor del compilador. Una buena regla general es hacer siempre que cada trazador de líneas, en particular todas las funciones que solo llaman una función, en línea, a medida que elimina la sobrecarga. Cualquier cosa por debajo de tres líneas de código lineal es casi seguro que está bien. Pero si tienes un bucle en el código, la pregunta es si el compilador lo permitirá en línea, y más al punto, cuánto beneficio verías incluso si hiciera lo que deseas.

consideran que este código en línea:

inline int add(int a, int b) { return a + b; } 

No es sólo casi tan pequeño como el prototipo estaría en el código fuente, pero el lenguaje ensamblador generado por el código en línea es más pequeña que la llamada a una rutina sería . Entonces este código es más pequeño y más rápido.

Y, si quedas pasando en constantes:

int c= add(5,4); 

Se resuelve en tiempo de compilación y no hay ningún código.

En gcc, recientemente me di cuenta de que incluso si no incluyo el código en línea, si es local para un archivo, de todos modos lo alinearán furtivamente. Es solo si declaro la función en un módulo de fuente separado que no optimizan la llamada.

En el otro extremo del espectro, suponga que solicita en línea un código de 1000 líneas. Incluso si su compilador es lo suficientemente tonto como para aceptarlo, lo único que ahorra es la llamada en sí, y el costo es que cada vez que lo llame, el compilador debe pegar todo ese código. Si llama ese código n veces , tu código crece según el tamaño de la rutina * n. Por lo tanto, no vale la pena destacar algo más grande que 10 líneas, excepto en el caso especial donde solo se llama un número muy pequeño de veces. Un ejemplo de eso podría ser un método privado llamado solo por otros 2.

Si solicita en línea un método que contiene un bucle, solo tiene sentido si a menudo se ejecuta un número pequeño de veces. Pero considere un ciclo que itera un millón de veces. Incluso si el código está en línea, el porcentaje de tiempo pasado en la llamada es muy pequeño. Por lo tanto, si tiene métodos con bucles, que tienden a ser más grandes de todos modos, vale la pena eliminarlos del archivo de encabezado porque a) tienden a ser rechazados por el compilador en línea yb) incluso si estaban en línea, son generalmente no va a proporcionar ningún beneficio

+0

Me has dejado sin palabras. Si defino una función de la manera normal (con una definición aquí y una implementación allá abajo), y pongo la palabra clave en línea al frente (¿de la definición de implementación ?, ¿ambas?), Entonces el compilador considerará incluirla en la lista. Y esto es mejor? Mi principal preocupación con las funciones en línea es que son feas y hacen que la línea sea larga. ¿Estás diciendo que puedo hacer que mis funciones normales parezcan fáciles de leer en línea ... y no solo eso, sino que debería marcar pequeñas funciones de esa manera? Espero que seas un usuario activo y respondas a este comentario. – Ziggy

+1

Si define una función usando un prototipo, con una implementación en el mismo archivo de encabezado marcada en línea, se hará en línea. Si su implementación está en otro archivo, el compilador no puede hacerlo en línea. No es un lector de mente, no sabe qué código generar. Personalmente, no me importa un pequeño código adicional en el encabezado en lugar de escribirlo dos veces, pero ciertamente puede hacerlo si lo prefiere. – Dov

+1

@ziggy si entiendo su pregunta correctamente, sí, si su función es corta, definirla en línea en el archivo de encabezado puede ser una gran ganancia de velocidad en tiempo de ejecución, mientras desacelera el tiempo de compilación ligeramente y también requiere los símbolos referenciados en el función en línea se define. Esto significa que si su código en línea se refiere a otros objetos, su encabezado podría tener que incluir otros encabezados. Entonces, hay un gran costo potencial en el tiempo de recompilación. Pero para el método promedio (getter/setter, calcular algo con las variables privadas), inline es una victoria masiva. – Dov