c++ - entrada - Inicializar una referencia-advertencia C4355: ''esto'': utilizado en la lista de inicializadores de miembros base
como se inicializa en c++ (5)
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() {
}
Actualmente, cuando intento inicializar la referencia en B, estoy usando el Método 1. Sin embargo, el Método 1 me marcará una advertencia que es comprensible.
Por lo tanto, tengo que retroceder usando el Método 2, usando la asignación de memoria dinámica.
¿Hay alguna forma mejor de usar sin la necesidad de asignación / deslocalización manual de memoria (OK. Sé que el puntero inteligente)?
Prefiero el Método 1, solo que no estoy cómodo con la advertencia.
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 del constructor de A se esté ejecutando. ...
Dependiendo de lo que esté haciendo, un método podría ser factorizar las partes de A
que B
necesita, de lo que A
heredará de la parte.
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és haciendo. Esto asegura que nunca tengas un comportamiento indefinido.
Pero en realidad, es solo una advertencia. Si prometes nunca usar this
en el constructor de B, estás bien y puedes silenciar la advertencia 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;
}
};
Aunque asegúrate de saber lo que estás haciendo. (Tal vez podría ser rediseñado?)
Hacer esto es válido.
Sin embargo, debe asegurarse (me refiero a usted mismo, no hay forma de que el compilador pueda hacer esto) que no se use para llamar a funciones virtuales hasta que el objeto esté completamente construido.
Tenga en cuenta que esto es una advertencia (por lo que es peligroso no ilegal).
Lo que le preocupa al compilador es que está pasando un puntero a un objeto que no se ha inicializado completamente. Por lo tanto, si el puntero se utiliza en el constructor de la clase B, se encuentra en un comportamiento indefinido.
Entonces, si usa esto, lo único que puede hacer es asignar el puntero a una variable miembro (referencia o puntero). Pero tenga en cuenta la asignación a una variable, ya que puede invocar una conversión implícita (no estoy seguro de que esto sea realmente un problema, pero el RTTI no está disponible hasta que el objeto esté completamente formado).
¿Qué intentas conseguir almacenando la referencia?
Tome en serio esta advertencia. Su objeto todavía no está completamente construido y su transmisión no es segura (si alguna vez llama accidentalmente a una función, invoca UB). Además, existen otras técnicas para la gestión de la memoria. Intenta buscar el diseño de asignadores STL.
También puede utilizar los punteros RAII / inteligentes para lograr el mismo efecto.
O, ¿estás tratando de escribir un recolector de basura / perfilador de memoria de clases?