views:

167

answers:

3

I have a class hierarchy where I know that a given class (B) will always be derived into a second one (D). In B's constructor, is it safe to statically cast the this pointer into a D* if I'm sure that nobody will ever try to use it before the entire construction is finished? In my case, I want to pass a reference to the object to yet another class (A).

struct A
{
    D & d_;

    A(D & d) : d_(d) {}
};

struct D; //forward declaration

struct B
{
    A a;

    B() : a(std::static_cast<D&>(*this)) {}
};

struct D : public B
{};

Is this code safe?

+3  A: 

No, it is not. Constructors for D's data members didn't run yet.

Since D's membrs aren't constructed, D isn't fully constructed yet, so technically, a reference to D should be invalid. I expect that to be no problem on most implementations, but still.

I'd like to suggest a better mechanism, but I guess "better" depends a lot on actual details.

peterchen
I know that D hasn't been constructed yet, that's why I precised that none of its member will be accessed before construction is over.
Luc Touraille
Regarding the validity of the this pointer in the initializer list, I also remember reading somewhere that it was unsafe to use it, but is it still true if no members are accessed? I'll try to find the paragraph in the standard that can answer this question.
Luc Touraille
Apparently, the standard explicitly states that 'this' can be used in the member-initializer-list to refer to the object being constructed.
Luc Touraille
I can't dig it up again, but I also can't reproduce it - I *think* the scenario was a bit different, maybe initializing a reference in the base class to a member in the derived class. Anyway, I'm removing the IIRC part, it's misleading. Thanks, Luc!
peterchen
+2  A: 

I didn't find anything about that. I've trouble to find reasons for which your code would be unsafe while this is safe:

struct B
{
    A a;

    B(D& d) : a(d) {}
};

struct D : public B
{
    D() : B(*this) {}
};

but I'd probably still use the form I present here.

AProgrammer
That's a nice way to avoid the static_cast, but the problem about the validity of this in the initializer list still holds. +1 for the cleaner way of writing it though.
Luc Touraille
A: 

@AProgrammer's answer made me realized that the static_cast could be easily avoided by passing the this pointer from the derived class to the base class. Consequently, the question boils down to the validity of the this pointer into the member-initializer-list.

I found the following note in the C++ Standard [12.6.2.7]:

[Note: because the mem-initializer are evaluated in the scope of the constructor, the this pointer can be used in the expression-list of a mem-initializer to refer to the object being initialized. ]

Therefore, using this in the member-initializer-list is perfectly valid, so I think the code presented is safe (as long as no members of D are accessed).

Luc Touraille