2010-03-22 12 views
5

Considere el siguiente código:¿Es un comportamiento indefinido en el caso de la llamada a funciones privadas en la lista de inicializadores?

struct Calc 
{ 
    Calc(const Arg1 & arg1, const Arg2 & arg2, /* */ const ArgN & argn) : 
     arg1(arg1), arg2(arg2), /* */ argn(argn), 
     coef1(get_coef1()), coef2(get_coef2()) 
    { 
    } 

    int Calc1(); 
    int Calc2(); 
    int Calc3(); 

private: 
    const Arg1 & arg1; 
    const Arg2 & arg2; 
    // ... 
    const ArgN & argn; 

    const int coef1; // I want to use const because 
    const int coef2; //  no modification is needed. 

    int get_coef1() const { 
    // calc coef1 using arg1, arg2, ..., argn; 
    // undefined behavior?  
    } 
    int get_coef2() const { 
    // calc coef2 using arg1, arg2, ..., argn and coef1; 
    // undefined behavior? 
    } 

}; 

struct Calc no está completamente definido cuando llamo get_coef1 y get_coef2 Es este código válido? ¿Puedo obtener UB?

+0

Funciona ... pero te preparas para problemas. ¿Qué sucede cuando llega el mantenedor, agrega 'argZ' después de los coeficientes, y luego usa' argZ' en el cálculo? Tendrá su UB ... –

Respuesta

8

12.6.2.8: Las funciones de miembro (incluidas las funciones de miembros virtuales, 10.3) se pueden llamar para un objeto en construcción. De forma similar, un objeto en construcción puede ser el operando del operador typeid (5.2.8) o de un dynamic_cast (5.2.7). Sin embargo, si estas operaciones se realizan en un inicializador de ctor (o en una función llamada directa o indirectamente desde un inicializador de ctor) antes de que se hayan completado todos los inicializadores de memoria para las clases base, el resultado de la operación no está definido.

Para que pueda inicializar los miembros de su clase de esta manera, pero no las clases base. Y, como señalaron otros, debe tener en cuenta el orden de inicialización de los miembros, si su función usa algunos de sus valores.

+0

+1 porque es más al punto de lo que el OP realmente quería saber. –

3

Dado que las variables de las que depende su cálculo ya están inicializadas en el momento de la llamada, no debe ser un comportamiento indefinido. Consulte la pregunta this para obtener información relacionada.

+3

Y tenga en cuenta que los miembros se inicializan en el orden en que aparecen sus declaraciones, no en el orden en que aparecen en la lista de inicializadores. Aquí es lo mismo, pero tenga en cuenta que simplemente poniendo 'const int coef;;' encima 'const Arg1 & arg1;' (y manteniendo la lista de inicializadores igual) * sería * create UB. –

+0

Mi pregunta no es sobre el orden de inicialización. El orden en que aparecen sus declaraciones está bien. Pregunto por las funciones 'get_calc1'. Es 'this'-pointer válido, por ejemplo? 'arg2' se inicializa, sí, es cierto. ¿Pero puedo acceder a 'arg2' en' get_calc1'? –

+1

Está perfectamente bien llamar a funciones miembro que solo se refieren a atributos de miembros inicializados. –

0

No es algo indefinido, pero debe estar absolutamente seguro de que esas funciones miembro solo están utilizando valores inicializados. Tenga en cuenta también que los valores se inicializan en el orden para que aparezcan en la claseno en el orden en que aparecen en la lista de inicialización. Por ejemplo:

struct Foo 
{ 
    int a, b; 
    int c; 
    Foo(): c(1), a(1), b(1) {} 
}; 

En ese constructor, las variables se inicializan en el orden a, b, entonces c, el orden en la lista no significa nada. Por lo tanto, si desea inicializar el valor de a utilizando algún cálculo en b y c, deberá mover la declaración de a a un punto posterior a b y c.

+0

Gracias. Pero mi pregunta no es sobre el orden de inicialización. Puede notar que la orden fue correcta. –

+0

Respondí eso en las primeras palabras. No está indefinido, siempre que el orden sea correcto, que es en su caso, así que está bien. –

Cuestiones relacionadas