2009-05-15 9 views
8

¿Hay algún problema al pasar 'esto' a otro objeto en la lista de inicializadores en el siguiente código?pasando esto desde la lista de inicializadores del constructor

class Callback { public: virtual void DoCallback() = 0; }; 

class B 
{ 
    Callback& cb; 
public: 
    B(Callback& callback) : cb(callback) {} 
    void StartThread(); 

    static void Thread() 
    { 
     while (!Shutdown()) 
     { 
      WaitForSomething(); 
      cb.DoCallback(); 
     } 
    } 
}; 

class A : public Callback 
{ 
    B b; 
public: 
    A() : b(*this) {b.StartThread();} 
    void DoCallback() {} 
}; 

Si no es seguro hacerlo, ¿cuál es la mejor alternativa?

Respuesta

10

Si usted es extremadamente cuidado, esto funcionará bien. Se meterá en muchos problemas si comienza a llamar a métodos virtuales o utiliza métodos que dependen de otros objetos del tipo. Pero si solo está estableciendo una referencia, esto debería funcionar bien.

Una alternativa más segura (pero no completamente segura) es establecer b más adelante una vez que se completa el constructor. Esto no eliminará los problemas de Vtable, pero eliminará problemas como el acceso a otras variables miembro antes de que se construyan.

class A : public Callback { 
    std::auto_ptr<B> spB; 
public: 
    A() { 
    spB.reset(new B(this)); 
    spB->StartThread(); 
    } 
}; 
0

Siempre que se asegure de que la referencia sigue siendo válida, esto es muy similar a una expresión idiomática llamada despacho doble. Puede ser excesivo en este caso, pero no tiene nada de intrínsecamente incorrecto.

6

Si la otra clase solo almacena el puntero/referencia, como en su caso, es seguro. Pero debe asegurarse de que los constructores/funciones a los que aprueba this no intenten acceder al objeto al que se hace referencia antes de que el constructor A finalice. El objeto A aún no está completamente construido y los métodos de llamada de A y el acceso a las propiedades pueden generar resultados indefinidos.

4

Generalmente es seguro si solo está guardando el puntero para usarlo más adelante. He hecho esto Yo no lo haría cualquiera de los siguientes:

  • usarlo para acceder a la base de datos de clase o derivados (que pueden no haber tenido sus constructores de ejecución)
  • hacer nada polimórfica, la viable no puede ser inicializado.

Here es un gran artículo de C++ FAQ que detalla los problemas con "esto" en los constructores.

+1

En algún momento entre entonces y ahora, el gran artículo del FAQ C++ ha migrado [aquí] (https: // isocpp .org/wiki/faq/ctors # using-this-in-ctors) – peterpi

2

Es lo suficientemente seguro, siempre que tenga en cuenta que el objeto this aún no se ha construido por completo. Si su clase B solo almacena el puntero, sin llamar a ninguna función en el constructor, está a salvo. Si intenta acceder al puntero desde el constructor de B, debe ser extremadamente cuidadoso y prestar atención al orden en que se inicializan los miembros de A.

3

El inicio de subprocesos en los constructores que ejecutan código en el objeto que todavía está bajo construcción es peligroso. El código que presentó funcionará correctamente tal como está, pero la solución es frágil.

Si DoCallback llama a un método virtual en A, puede terminar obteniendo resultados inesperados según la velocidad de ejecución del subproceso. Si el método llamado es puramente virtual, la aplicación morirá; si no es pura, se llamará a la versión A del método en lugar de a la versión derivada. Esa es exactamente la misma razón por la que nunca debe llamar a un método virtual desde un constructor.

El enfoque más seguro es hacer que el usuario llame al hilo. Ese es también el enfoque en la biblioteca boost :: thread y el próximo estándar.Crear e inicializar el objeto que va a ser ejecutado y luego pasarlo al hilo conductor:

class Worker 
{ 
public: 
    void DoWork(); 
}; 
void startWorkerThread() 
{ 
    Worker w; // fully create the object that is going to be run before you... 
    boost::thread thr(boost::bind(&Worker::DoWork, &w)); // ...create thread and run 
} 
Cuestiones relacionadas