Home > Mobile >  Constructing objects with mutual references to each other
Constructing objects with mutual references to each other

Time:07-19

I've run into a bit of a chicken and the egg scenario.

Say I have these two classes

class A{
public:
    A(B& );
private:
    B& ref;
};

class B{
public:
    B(A& );
private:
    A& ref;
};

Is there any way for me to initialize them? Because the fields are references, I have to bind them in the member initializer list so they can never be null. However, I can't make either one of them without the other, so I can't even supply the references.

Currently, I have two thoughts. The first is that I can switch one of the fields to a raw pointer, that way I can just supply a nullptr and bind it later in a method. However this weakens my null safety so I don't really want to do that. My second thought was that I could just declare a variable without initializing it, so something like

A foo;
B bar(foo);
foo(bar);

where I just construct it later. Unfortunately, this calls a default constructor on the first line, which isn't provided, so this doesn't work.

So I would like some advice on getting my current ideas to work, or if there's a built-in mechanism in C for this that I don't know about.

CodePudding user response:

Its a chicken and egg problem. You need an A to create a B and you need a B to create an A.

However, if you always create an A and a B together, then I would suggest, as already mentioned in a comment, to wrap them in a class. Then you can use the member initializer list:

struct B;

struct A {
    A(B& b) : ref(b) {}
    B& ref;
};

struct B {
    B(A& a) : ref(a) {}
    A& ref;
};

struct AB {
    A a;
    B b;
    AB() : a(b),b(a) {}
};

Using the reference to member b before it has been initialized is fine as long as A only stores the reference and does not read from it or call methods.

However, once they are wrapped in the same class it is kind of pointless to have them store references to each other.

Moreover reference members have certain unpleasant implications (eg no copies). Consider if thats what you really like or if perhaps pointers are fine.

CodePudding user response:

If you are trying to create a loop dependency then at least one of the members will need to be a pointer. But it is otherwise fully possible to have this work by using forward declarations.

class B;
extern B b;

class A
{
public:
    A(B & b)
        : b(b)
    {
    }

private:
    B & b;
};

class B
{
public:
    B(A & a)
        : a(a)
    {
    }

private:
    A & a;
};

A a(b);
B b(a);
  • Related