8

I have a parent object that has some other objects as fields. The parent object fully owns these fields: they can be declared as fields of the parent object (MyPart part), directly, not as references.

I would prefer to initialize these fields in constructor, but in some cases they do need to reach the parent object instance and call methods on it as they work. With raw pointers, I could simply pass this to they constructors or setters. I have just discovered however that creating smart pointer from this is something near impossible, because such pointer would not know when the parent object goes out of scope (for sure not where the constructor returns!). But I do known that being the fields of the parent object, these children definitely cannot outlive it.

The only "clean" idea I can so far imagine is to construct the object in some factory method where reference to the constructed parent can be a smart pointner, then construct children separately and use the setter to compose the parent. Is this really the best approach?

As we have now policy to avoid raw pointers at all costs, what other options could I have? Or just using raw pointers in such a case is appropriate?

3
  • 2
    Use a reference Parent&, and pass it *this if you truly need access to the parent. If the child needs access to the parent through a std::shared_ptr<>, you can have the parent inherit std::enable_shared_from_this see here. This will allow a shared_ptr to be constructed by this->shared_from_this(). Unless you are implementing a data structure this is almost certainly poorly designed. Whatever child needs of Parent try and extract it into a common class, this way it can be fully constructed before use.
    – Kain0_0
    Commented Mar 22, 2019 at 6:00
  • 3
    Raw pointers shouldn’t own data (because you could forget to delete them), but it’s fine to use them to reference data or to access data.
    – Alecto
    Commented Mar 22, 2019 at 7:42
  • 2
    A policy to "avoid raw pointers at all costs" may have been well-intentioned - but it is controversial, and in modern C++, unnecessary as the use of a raw pointer now has a definite meaning: This pointer does not own the object pointed to. With that meaning there is no ambiguity about whether you should free (i.e., delete) one or not: You shouldn't. Here are B. Stroustrup's arguments for dropping observer_ptr - which was intended for this kind of thing - and just using raw pointer notation (pdf).
    – davidbak
    Commented Nov 27, 2020 at 0:54

4 Answers 4

17

You can use a reference to the parent. As a sketch

class Parent;

class Child {
private: 
    Parent & parent;
public:
    Child(Parent & p) : parent(p) {}
    // other members
};

class Parent {
private:
    Child child;
public:
    Parent() : child(*this) {}
    // other members
};

As a bonus, the compiler will refuse to let you construct a Child without a Parent. You can go further, and make Child only privately constructable, and friend Parent.

11
  • 1
    The problem with using a reference is that Child is not assignable anymore. Using a pointer member variable avoids that.
    – D Drmmr
    Commented Mar 23, 2019 at 20:02
  • @DDrmmr? it's a subobject of Parent, it doesn't need to be assignable
    – Caleth
    Commented Mar 23, 2019 at 20:44
  • Bracket missing at the start of Parent. =)
    – Elliott
    Commented Feb 2, 2021 at 4:00
  • Reference as member is only valid during the expression which created it. It is a cause of undefined behavior in the next valid expression. It is not because the referenced object goes out of scope, it is just the rule of the language. This needs to be handled using pointers or copy semantics instead. There is an entire paragraph describing the UB caused by keeping member reference in 14882:2003 that I'm too lazy to search for.
    – nurettin
    Commented Nov 23, 2021 at 7:38
  • @nurettin child is created with a valid reference to the Parent object, and is destroyed strictly before the Parent. Did you miss the part where child is a data member of the Parent object?
    – Caleth
    Commented Nov 23, 2021 at 9:13
13

Just use a raw pointer, it is a non-owning pointer that has no implication on life-cycle.

And the child holding a parent pointer will not outlive the parent as you say they are non-pointer/reference members so parent will clean them up.

0
9

Try to avoid coupling the field classes to the parent class. Any data that is in the parent, but is needed by the field, can be passed when calling a function of the field. Any function of the parent that needs to be called by a function of the field can be passed as a callback function (e.g. using std::function).

A mutual dependency between classes is often an indication that the code is ill structured. The flow of the program can quickly become unwieldy, making the code hard to maintain.

If the field really needs a reference to the parent, you can safely pass the this pointer to the field's constructor (even in the parent's initializer list), provided the field's constructor doesn't access the passed pointer, but only stores it.

1

I think you can use mix of non-const reference and non-static data member initialization.

#include <iostream>
using namespace std;

class Parent;
class Child {
private:
    Parent& parent;
public:
    Child(Parent& parent): parent(parent) { cout << "Child ctor" << endl; };
    ~Child() { cout << "Child dtor" << endl; } ;
};

class Parent {
private:
    Child child { Child(*this) };
public:
    Parent (){ cout << "Parent ctor" << endl; };
    ~Parent() { cout << "Parent dtor" << endl; } ;
};

int main(int argc, char *argv[]) {
    Parent parent;
}

output:

~$ g++ -o test test.cpp -std=c++11 && ./test
Child ctor
Parent ctor
Parent dtor
Child dtor

Not the answer you're looking for? Browse other questions tagged or ask your own question.