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.
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?
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.
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?)
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....
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With