2010-11-10 13 views
6

mi código:está 'dando' una referencia a 'esto' dentro del constructor ¿está bien?

Scene::Scene(const std::string &scene_file) : ambient_light(0, 0, 0), background(0, 0, 0){ 
    scene_parser parser(*this); 
    parser.parse(scene_file); 
} 

scene_parser es un amigo de la escena, y en el método de análisis que tiene acceso (r/w) los miembros de la escena. ¿Esto va a causar algún problema?

+0

Debe señalarse que esto está bien siempre que proporcione el puntero 'this' desde el cuerpo del constructor, y no desde la lista de inicialización. –

+0

también verifique qué C++ faq-lite tiene que decir: http://www.parashift.com/c++faq-lite/ctors.html#faq-10.7 – stefaanv

Respuesta

4

En su ejemplo particular, no debería surgir ningún problema.

En general, el problema con dar this referencias es que las vidas de los dos objetos no se alinean exactamente y el otro objeto podría intentar acceder al objeto referido después de que ya se ha destruido.

En su ejemplo, el objeto scene_parser está en la pila, por lo que su vida útil finaliza al final del constructor Scene. No hay forma posible de que intente acceder a un objeto inexistente a través de la referencia this que proporcionó, por lo que no puede surgir ningún problema.

+3

No, pero si 'parser' invoca funciones' virtuales', no obtendrá el efecto deseado. Aunque ese * es * legal, usted podría (y probablemente debería) considerarlo un error. –

+0

Esa es una posible oportunidad de dar cualquier puntero en absoluto, nada específico para los constructores o el puntero 'this'. El verdadero problema con regalar 'this' del constructor es que las funciones miembro de la clase podrían llamarse antes de que el constructor termine de establecer invariantes. –

+1

No tengo la intención de subclasificar Escena, por lo que parece que todo está bien. – Bwmat

8

Sí, está bien dar una referencia a this. Sin embargo, generalmente quiere hacer eso cuando el otro objeto usará el puntero más tarde. Su caso de uso parece que usará el Scene inmediatamente, antes de que el constructor complete, que es una pendiente muy resbaladiza.

En este momento, no está estableciendo ninguna invariante después de llamar al parse, por lo que debería estar bien, pero también es frágil y fácil para los cambios futuros para introducir la rotura.

+0

Buena respuesta. Creo que debería incluir parte de la información que proporciona en los comentarios a otras respuestas, ya que parece que hay algunas sutilezas que deben abordarse. –

+2

@voodooclock: las advertencias relacionadas con las funciones virtuales en realidad no requieren pasar el puntero 'this' a ningún otro objeto. Puede tener problemas para invocar las funciones propias de la clase desde dentro del constructor. Además, el OP ya ha indicado que 'Scene' es una clase de terminal, por lo que el tipo dinámico del objeto no será un problema. –

+0

Ah, gracias por la aclaración. Estaba leyendo demasiado sobre eso. –

1

Depende.

Dentro del cuerpo del constructor (es decir, una vez que se ejecuta la lista de inicializadores), el objeto se considera "totalmente construido" hasta el tipo actual. Por lo tanto, puede referencia *this, pero cualquier llamada a función virtual no utilizará funciones anuladas en clases derivadas.

+2

Creo que lo retrasaste en las llamadas a funciones virtuales, pero eso es algo importante que debes tener en cuenta. –

+0

@Ben: tienes razón, escribí "base" en lugar de "derivada". –

0

Todos sus subobjetos (miembros y bases) se construyen con la primera instrucción en el cuerpo del constructor. Si su objeto está en un "estado válido" (que es parte de la definición de su clase, algunas veces llamada "invariante de clase") en este punto, puede tratarlo como un objeto completamente construido y hacer cualquier cosa con él. Sin embargo, la búsqueda virtual funciona de forma ligeramente diferente a lo que puede esperar o requerir: si se trata de una clase base (y por lo tanto este objeto es un subobjeto de otra cosa), el tipo final aún no se ha "asignado". Por ejemplo, esta es una forma de llamar a métodos puramente virtuales y obtener un error de tiempo de ejecución (si esos métodos no tienen definiciones, de todos modos).

Una situación más interesante es usar este en el inicializador de constructor; eso tiene algunas advertencias, pero eso también está antes del cuerpo constructor.

Cuestiones relacionadas