64

I have two classes with a parent-child relationship (the Parent class "has-a" Child class), and the Child class has a pointer back to the Parent. It would be nice to initialize the parent pointer upon construction of the child, as follows:

class Child;
class Parent;

class Child
{
public:
 Child (Parent* parent_ptr_) : parent_ptr(parent_ptr_) {};

private:
 Parent* parent_ptr;
};

class Parent
{
public:
    Parent() : child(this) {};

private:
    Child child;
}

Now, I know people recommend not using this in initialization list, and C++ FAQ says I'm gonna get a compiler warning (BTW, on VS2010, I don't get a warning), but I really like this better then calling some set function in Parent's constructor. My questions are:

  • Is the parent this pointer well-defined when the Child object is being created?
  • If so, why is it considered bad practice to use it as above?

Thanks,

Boaz

EDIT: Thanks Timbo, it is indeed a duplicate (huh, I even chose the same class names). So lets get some added value: how about references? Is it possible / safe to do the following? :

class Child
{
public:
 Child (Parent& parnet_ptr_) : parent_ptr(parent_ptr_) {};

private:
 Parent* parent_ptr;
};

class Parent
{
public:
    Parent() : child(*this) {};

private:
    Child child;
}
BYS2
  • 5,199
  • 5
  • 24
  • 32
bavaza
  • 10,319
  • 10
  • 64
  • 103
  • possible duplicate of [In C++, initialize a class member with 'this' pointer during construction.](http://stackoverflow.com/questions/4006160/in-c-initialize-a-class-member-with-this-pointer-during-construction) – Timbo Feb 20 '11 at 16:38
  • @thecoshman - pun intended? – bavaza Jul 19 '16 at 08:03
  • vs2010 actually does produce warning on this, it depends on warning level that was set – Swift - Friday Pie Feb 01 '17 at 11:30

3 Answers3

65

Yes. It's safe to use this pointer in initialization-list as long as it's not being used to access uninitialized members or virtual functions, directly or indirectly, as the object is not yet fully constructed. The object child can store the this pointer of Parent for later use!

Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • 2
    It's also unsafe to call virtual functions in the parent before the parent's construction is finished. – Pontus Gagge Feb 20 '11 at 16:37
  • 4
    In short. The child **CAN NOT** use this pointer in its constructor/destructor but otherwise it is OK. – Martin York Feb 20 '11 at 18:35
  • does this in turn imply that it is fine to use it to access already initialized members? For example `struct foo { int x,y; foo(int z) : x(z), y(this->x) {} };` or how about using `this` to refer to the member as in this case: `struct foo { int x; foo(int z) : this->x(z) {} };` ? – 463035818_is_not_an_ai Jun 12 '19 at 11:37
  • `y(this->x)` is perfectly fine. and why would you do `this->x(z)` though when `x(z)` is enough and means the same thing? I dont even know if the compiler would allow you to write `this->x(z)`. – Nawaz Jun 13 '19 at 06:13
  • It appears `this->x(z)` is invalid. It would have been useful if the member variable shares the same name as a constructor argument, which is quite common. I.e. `this->x(x)` instead of `x(x)` – Rufus Nov 12 '20 at 05:33
  • In the init-list, you cannot use `this`. So use `x(x)`, not `this->x(x)`. [Note that `x(x)` is correct, the compiler knows which `x` is param and which `x` is member, so will do the right thing](https://stackoverflow.com/a/6185043/415784) – Nawaz Nov 12 '20 at 08:39
14

The parent this pointer, in "pointer terms", is well-defined (otherwise how would the parent constructor know on which instance is it operating?), but:

  • the fields that are declared after the Child object aren't initialized yet;
  • the code in the constructor hasn't run yet;
  • also, the usual warnings about using virtual members from the constructor apply1.

So, the parent object in general is still in an inconsistent state; everything the child object will do on construction on the parent object, will be done on a half-constructed object, and this in general isn't a good thing (e.g. if it calls "normal" methods - that rely on the fact that the object is fully constructed - you may get in "impossible" code paths).

Still, if all the child object do with the parent pointer in its constructor is to store it to be use it later (=> when it will be actually constructed), there's nothing wrong with it.


  1. I.e., virtual dispatch doesn't work in constructors, because the vtable hasn't been updated yet by the derived class constructor. See e.g. here.
Matteo Italia
  • 123,740
  • 17
  • 206
  • 299
  • @Matteo Italia : +1. By the way, why did you keep third point in parentheses? That is as important as others. Remove the parentheses! – Nawaz Feb 20 '11 at 16:46
  • @Nawaz: thank you, parentheses removed (BTW, you too got my +1 before I started writing `:)`). The parens were there because it wasn't a warning *specific* to this scenario, but general about virtual functions and constructors; it was a "just in case you didn't remember it" advice. `:)` – Matteo Italia Feb 20 '11 at 16:48
  • Question - is it the order of field declarations, or the order of initialisers, that is significant? I thought the latter (where they are present), but it's been a while since I worried about it. –  Feb 20 '11 at 17:08
  • @Steve: ((I think you're correct))(Or maybe, I do (not) think the (way) you think). – Nawaz Feb 20 '11 at 17:21
  • 1
    @Steve314: it's the order of field declarations, not of the initializers. Actually, if you specify different orders most compilers (in "paranoid warnings mode") will issue a warning that reminds you this. – Matteo Italia Feb 20 '11 at 17:27
  • @Matteo - thanks. @Nawaz - No-one thinks the way I think! Why would anyone want to? –  Feb 20 '11 at 17:35
  • @Steve, @Nawaz: probably you two have different overloads of the parentheses (function call) operators. :S – Matteo Italia Feb 20 '11 at 17:43
5

The behaviour is well-defined so long as you don't attempt to dereference the pointer until after the Parent object has been completely constructed (as @Sergey says in a comment below, if the object being constructed is actually derived from Parent, then all of its constructors must have completed).

Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
  • 1
    Not exactly the Parent constructor. Strictly speaking, accessing the pointer freely is only guaranteed to be safe after all the object's constructors have completed. In the Parent constructor we have no way to know if it's actually a Parent being constructed or possibly some distant subclass of it that has its fields and possibly reimplements some virtual functions defined in the Parent. – Sergei Tachenov Feb 20 '11 at 16:54
  • @Sergey: That's a *very* good point. I will update my answer. – Oliver Charlesworth Feb 20 '11 at 16:58