2010-08-18 17 views
16
class A; 

class B { 
public: 
    B(A& a) : a(a) {} 
private: 
    A& a; 
}; 

/* Method 1 */ 
/* warning C4355: 'this' : used in base member initializer list */ 
/* 
class A { 
public: 
    A() : b(*this) {} 

private: 
    B b; 
}; 
*/ 

/* Method 2 */ 
/* But I need to manually perform memory dellocation. */ 
class A { 
public: 
    A() { b = new B(*this); } 
    ~A() { delete b; } 

private: 
    B* b; 
}; 

int main() { 
} 

En la actualidad, cuando intento inicializar la referencia en B, estoy usando el método 1. Sin embargo, el método 1 voluntad bandera advirtiéndome cuales es entendible.Iniciar una referencia - C4355 advertencia: 'esto': se utiliza en lista de inicialización miembro de base

Por lo tanto, tengo que recurrir al método 2, mediante la asignación dinámica de memoria.

¿Hay alguna manera mejor que pueda usar, sin la necesidad de asignación/asignación de memoria manual (OK, conozco el puntero inteligente)?

Prefiero el Método 1, solo que no me siento cómodo con la advertencia.

Respuesta

12

Tenga en cuenta que esto es una advertencia (por lo que es peligroso, no es ilegal).

Lo que le preocupa al compilador es que está pasando un puntero por un objeto que no se ha inicializado por completo. Por lo tanto, si el puntero se utiliza en el constructor de clase B, tiene un comportamiento indefinido.

Así que si utiliza esto, lo único que puede hacer es asignar el puntero a una variable miembro (referencia o puntero). Pero note tenga cuidado con la asignación a una variable ya que puede invocar un molde implícito (no estoy seguro si eso es realmente un problema pero el RTTI no está disponible hasta que el objeto esté completamente formado).

¿Qué intenta lograr almacenando la referencia?

8

Hacer esto es válido.

Sin embargo, debe asegurarse (me refiero a usted, el compilador no puede hacer esto) de que el this no se usa para llamar funciones virtuales hasta que el objeto esté completamente construido.

1

Bueno, una manera obvia de evitar la advertencia es hacer que B almacene un puntero-a-A, entonces no tiene que inicializarlo en la lista de inicializadores del constructor/A de B, y puede esperar hasta que el cuerpo de A constructor se está ejecutando ...

0

Tome en serio esta advertencia. Su objeto this aún no está completamente construido y el paso no es seguro (si alguna vez llama accidentalmente a una función en this, llama a UB). Además, hay otras técnicas para la gestión de la memoria. Intente buscar el diseño de los asignadores de STL.

También podría utilizar RAII/punteros inteligentes para lograr el mismo efecto.

¿O está tratando de escribir un tipo de recolector de basura/generador de perfiles de memoria?

6

Dependiendo de lo que esté haciendo, un método podría ser factorizar las partes de A que B necesita, que tener A heredar de la pieza.

struct bar_base; // interface foo wants 

struct foo 
{ 
    foo(bar_base& pX) : 
    mX(pX) 
    {} 

    bar_base& mX; 
}; 

struct bar_base 
{ 
    /* whatever else */ 
protected: 
    bar_base& get_base(void) 
    { 
     // getting `this` went here; safe because bar_base is initialized 
     return *this; 
    } 
}; 

struct bar : bar_base 
{ 
    bar(void) : 
    // bar_base is already initialized, so: 
    mX(get_base()) 
    {} 

    foo mX; 
}; 

Obviamente, esto depende de lo que esté haciendo. Esto asegura que nunca tengas un comportamiento indefinido.

Pero realmente, es solo una advertencia.Si usted se compromete a utilizar nunca más this en el constructor de B, que estás bien, y puede silenciar el aviso de esta manera:

struct bar; 

struct foo 
{ 
    foo(bar& pX) : 
    mX(pX) 
    {} 

    bar& mX; 
}; 

struct bar 
{ 
    bar(void) : 
    mX(self()) 
    {} 

    foo mX; 

private: 
    bar& self(void) 
    { 
     // fools the warning 
     return *this; 
    } 
}; 

Asegúrese de saber lo que está haciendo, sin embargo. (Tal vez podría ser rediseñado?)

Cuestiones relacionadas