c++ function methods inline deprecated

c++ - ¿Todavía hay un uso para en línea?



function methods (2)

Trataré de explicar mi "comprensión secreta" de la mejor manera que pueda.

Hay dos conceptos completamente separados aquí. Una es la capacidad del compilador para reemplazar una llamada a la función repitiendo el cuerpo de la función directamente en el sitio de la llamada. La otra es la posibilidad de definir una función en más de una unidad de traducción (= más de un archivo .cpp ).

El primero se llama función en línea. El segundo es el propósito de la palabra clave en inline . Históricamente, la palabra clave en inline también fue una fuerte sugerencia para el compilador de que debería alinear la función marcada en inline . A medida que los compiladores se volvieron mejores en la optimización, esta funcionalidad ha retrocedido, y el uso de en inline como una sugerencia para incorporar una función es obsoleto. El compilador felizmente lo ignorará e incorporará algo completamente diferente si encuentra que es una mejor optimización.

Espero que hayamos tratado con la relación explícita en inline inclinación. No hay ninguno en el código actual.

Entonces, ¿cuál es el propósito real de la palabra clave en inline ? Es simple: una función marcada en inline se puede definir en más de una unidad de traducción sin violar la Regla de una definición (ODR). Imagine estos dos archivos:

file1.cpp

int f() { return 42; } int main() { return f(); }

file2.cpp

int f() { return 42; }

Este comando:

> gcc file1.cpp file2.cpp

Producirá un error de enlazador, quejándose de que el símbolo f se define dos veces.

Sin embargo, si marca una función con la palabra clave en inline , le dice específicamente al compilador y al enlazador: "¡Ustedes se aseguran de que múltiples definiciones idénticas de esta función no den lugar a ningún error!"

Entonces lo siguiente funcionará:

file1.cpp

inline int f() { return 42; } int main() { return f(); }

file2.cpp

inline int f() { return 42; }

Compilar y vincular estos dos archivos juntos no producirá ningún error de vinculador.

Tenga en cuenta que, por supuesto, la definición de f no tiene que estar literalmente en los archivos. En su lugar, puede provenir de un archivo de encabezado #include d:

f.hpp

inline int f() { return 42; }

file1.cpp

#include "f.hpp" int main() { return f(); }

file2.cpp

#include "f.hpp"

Básicamente, para poder escribir una definición de función en un archivo de encabezado, debe marcarla como en inline , de lo contrario, se generarán múltiples errores de definición.

La última pieza del rompecabezas es: ¿por qué la palabra clave realmente se escribe en inline cuando no tiene nada que ver con la inlínea? La razón es simple: para alinear una función (es decir, para reemplazar una llamada repitiendo su cuerpo en el sitio de la llamada), el compilador debe tener el cuerpo de la función en primer lugar.

C ++ sigue un modelo de compilación separado, donde el compilador no tiene acceso a archivos de objetos que no sean el que está produciendo actualmente. Por lo tanto, para poder en línea una función, su definición debe ser parte de la unidad de traducción actual. Si desea poder incorporarlo en más de una unidad de traducción, su definición debe estar en todas ellas. Normalmente, esto llevaría a un error de definición múltiple. Entonces, si coloca su función en un encabezado e #include su definición en todas partes para habilitar su alineación en todas partes, debe marcarla como en inline para evitar errores de definición múltiple.

Tenga en cuenta que incluso hoy, aunque un compilador incorporará cualquier función que considere adecuada, aún debe tener acceso a la definición de esa función. Por lo tanto, aunque la palabra clave en inline no es necesaria ya que la sugerencia "por favor, incluya esto", es posible que todavía necesite usarla para permitir que el compilador haga la línea si así lo desea. Sin ella, es posible que no pueda obtener la definición en la unidad de traducción, y sin la definición, el compilador simplemente no puede alinear la función.

El compilador no puede. El enlazador puede. Las técnicas de optimización modernas incluyen Generación de código de tiempo de enlace (también conocido como Optimización de todo el programa), donde el optimizador se ejecuta sobre todos los archivos de objetos como parte del proceso de enlace, antes del enlace real. En este paso, todas las definiciones de funciones están disponibles, por supuesto, y la alineación es perfectamente posible sin que se use una sola palabra clave en inline en cualquier parte del programa. Pero esta optimización es generalmente costosa en tiempo de construcción, especialmente para proyectos grandes. Con esto en mente, depender únicamente de LTCG para la alineación puede no ser la mejor opción.

Para completar: he hecho un poco de trampa en la primera parte. La propiedad ODR no es en realidad una propiedad de la palabra clave en inline , sino de funciones en línea (que es un término del lenguaje). Las reglas para las funciones en línea son:

  • Se puede definir en varias unidades de traducción sin causar errores de enlace
  • Debe definirse en cada unidad de traducción en la que se utiliza
  • Todas sus definiciones deben ser token por token y entidad por entidad idénticas

La palabra clave en inline convierte una función en una función en línea. Otra forma de marcar una función como en línea es definirla (no solo declararla) directamente en una definición de clase. Dicha función está en línea automáticamente, incluso sin la palabra clave en inline .

Esta pregunta ya tiene una respuesta aquí:

Creí, en inline era obsoleto porque leí here :

No importa cómo designe una función como en inline , es una solicitud que el compilador puede ignorar: el compilador puede expandir en línea algunos, todos o ninguno de los lugares donde llama a una función designada como en inline .

Sin embargo, Angew parece entender algo que yo no. En esta pregunta, él y yo vamos y venimos un poco, sobre si en inline sigue siendo útil.

Esta pregunta no es una pregunta sobre:

  • El uso histórico de inline o donde inline todavía se podría usar para indicar al compilador que inline funciones: ¿ Cuándo debo escribir la palabra clave ''inline'' para una función / método? .
  • Los beneficios o inconvenientes del código de función en línea : ¿ Beneficios de las funciones en línea en C ++?
  • Obligar al compilador al código de función en inline : forzar la función en línea en otra unidad de traducción

Teniendo en cuenta que el compilador puede en inline a voluntad, por lo que no es útil en inline : ¿Dónde se puede usar en inline para forzar, no sugerir , un cambio en el código compilado?


inline es principalmente un especificador de vinculación externo, por las razones que usted indicó.

Entonces, sí, tiene un uso, pero es diferente de las funciones realmente en línea. Le permite definir el mismo método varias veces entre unidades de compilación y vincularlas correctamente, en lugar de obtener múltiples errores de definición.

//header.h inline void foo() {} void goo() {} //cpp1.cpp #include "header.h" //cpp2.cpp #include "header.h" // foo is okay, goo breaks the one definition rule (ODR)

En realidad, forzar la función en línea depende del compilador, algunos pueden tener soporte a través de attribute específicos o pragma s o ( __forceinline ) o cualquier otra cosa.

En pocas palabras, le permite definir funciones en encabezados sin romper el ODR ...