2012-06-26 10 views
9

código mínimo:¿Es un comportamiento indefinido tener diferentes definiciones de una función en línea?

// --------inline.h-------- 
struct X { 
    static inline void foo(); 
}; 
#ifdef YES 
inline void X::foo() { cout << "YES\n"; } 
#else 
inline void X::foo() { cout << "NO\n"; } 
#endif 

// --------file1.cpp-------- 
#define YES // <---- 
#include"inline.h" 
void fun1() 
{ 
    X::foo(); 
} 

// --------file2.cpp-------- 
#include"inline.h" 
void fun2() 
{ 
    X::foo(); 
} 

Si llamamos fun1() y fun2(), entonces van a imprimir y YESNO respectivamente, lo que significa que se están refiriendo diferentes cuerpos de las funciones del mismo X::foo().

Independientemente de esto debe codificarse o no, mi pregunta es:
¿Es este un comportamiento bien definido o indefinido?

+0

Si desea tener dos funciones libres diferentes (no miembros de clase) en dos archivos diferentes pero con el mismo nombre, puede aislarlos con la palabra clave 'static' (o un espacio de nombre anónimo). Marcar una función en file2.cpp como estática significa que ningún otro archivo .cpp puede verla durante la vinculación. Eso es útil para programas muy grandes en los que no siempre se puede estar seguro de qué nombres comunes ya han sido asumidos por las funciones. – Crashworks

+0

Realmente no necesita inline.h y el #define hack en este caso; simplemente defina "void X :: foo()" (con o sin la línea) de una manera en file1.cpp, y la otra en file2.cpp, y tendrá exactamente el mismo comportamiento. – abarnert

+0

@abarnert: Omitir los resultados 'en línea' en una violación diferente de la regla de una definición. Las funciones no en línea están cubiertas por 3.2 párrafo 3, funciones en línea por 3.2 párrafo 5. Muchos (¿la mayoría?) Enlazadores atrapan las violaciones no en línea. El mío al menos no detecta las violaciones en línea. –

Respuesta

13

Sí, es Comportamiento indefinido.

Referencia:

C++ 03 estándar:

7.1.2 especificadores de función [dcl.fct.spec]
Para 4:

Se debe definir una función en línea en cada unidad de traducción en la que se utiliza y debe tener 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 externa en línea 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.

Nota: 3.2 se refiere a la regla de una definición, que establece:

3.2 Una regla definición [basic.def.odr]
Para 1:

n La unidad de traducción contendrá más de una definición de cualquier variable, función, tipo de clase, tipo de enumeración o plantilla.

+0

+1. Además, tenga en cuenta que inline es solo una pista (aunque también puede engañar al compilador y/o al enlazador para que pierda una buena oportunidad para advertirle en este caso). – abarnert

+3

@abarnert: 'inline' es mucho más que una sugerencia. Si la llamada de función se reemplaza por el cuerpo de la función queda a criterio del compilador, pero una vez que se usa' inline' el compilador ** debe ** seguir ciertas reglas wrt One Definition Regla. –

+0

Sí, pero lo que dicen las reglas es que usar inline no puede guiarlo por la ODR, excepto en el sentido trivial de que puede repetir exactamente la misma definición. – abarnert

7

Indefinido. Usted está violando la ODR.

4

Si llamamos fun1() y fun2(), entonces van a imprimir SÍ y NO, respectivamente, lo que significa que se están refiriendo diferentes cuerpos de las funciones del mismo X :: foo().

¿Lo intentó? Con diferentes niveles de optimización?

Recibo SÍ y NO, SÍ y SÍ, o NO y NO según el nivel de optimización y el orden en que se presentan los objetos compilados al vinculador.

No hace falta decir que esto es un comportamiento indefinido.

+0

+1 por esta información. No me di cuenta de eso. Compilé con '-O4'. – iammilind

+1

@ Alls: observar un comportamiento salvajemente variable es una buena evidencia (si no del todo) de un comportamiento indefinido. Es lo contrario que es peligroso (observar un comportamiento consistente no es una buena evidencia de que no se trata de un comportamiento indefinido). – abarnert

+3

@Als: me doy cuenta de que el comportamiento observado no es una prueba. Sabía que esto era UB de antemano. Pensé que sería interesante ver lo que se produjo y ver cómo jugar con él para que produzca resultados diferentes. –

Cuestiones relacionadas