Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initialize a reference - warning C4355: 'this' : used in base member initializer list

Tags:

c++

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() {
}

Currently, when I try to initialize the reference in B, I am using Method 1. However, Method 1 will flag me warning which is understandable.

Hence, I have to fall back using Method 2, by using dynamic memory allocation.

Is there any better way I can use, without the need of manual memory allocation/ dellocation (OK. I know smart pointer)?

I prefer Method 1, just that I am not comfortable with the warning.

like image 866
Cheok Yan Cheng Avatar asked Aug 18 '10 06:08

Cheok Yan Cheng


4 Answers

Note this is a warning (so it is dangerous not illegal).

What the compiler is worried about is that you are passing a pointer for an object that has not been fully initialized. Thus if the pointer is used in the B class constructor you are in undefined behavior.

So if you do use this the only thing you can do is assign the pointer to a member variable (reference or pointer). But note be careful of the assignment to a variable as you may invoke an implicit cast (I am not sure if that is actually a problem but the RTTI is not available until the object is fully formed).

What are you trying to achieve by storing the reference?

like image 64
Martin York Avatar answered Nov 13 '22 07:11

Martin York


Doing this is valid.

However, you must ensure (I mean by yourself, there's no way the compiler can do this) that the this is not used to call virtual functions until the object is fully constructed.

like image 26
Didier Trosset Avatar answered Nov 13 '22 09:11

Didier Trosset


Depending on what you're doing, a method might be to factor out the parts of A that B needs, than have A inherit from the part.

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;
};

Obviously, this depends on what you're doing. This makes sure you never get undefined behavior.

But really, it's just warning. If you promise to never use this in B's constructor, you're fine, and can silence the warning this way:

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;
    }
};

Make sure you know what you're doing, though. (Perhaps it could be re-designed?)

like image 7
GManNickG Avatar answered Nov 13 '22 07:11

GManNickG


Well, one obvious way to avoid the warning is to make B store a pointer-to-A, then you don't have to initialise it in B's constructor/A's initialiser list, and can wait until the body of A's constructor is executing....

like image 2
Tony Delroy Avatar answered Nov 13 '22 07:11

Tony Delroy