6

For example, I have two classes

class Foo;
class Bar;

class Foo {
  const Bar &m_bar;
  ...
};

class Bar {
  const Foo &m_foo;
  ...
};

Let foo is object of Foo and bar is object of Bar. Is there any way (normal or "hacking") to create/initialize foo and bar that their members m_bar and m_foo would referenced to each other (I mean foo.m_bar is bar and bar.m_foo is 'foo')?

It is allowed to add any members to Foo and Bar, to add parents for them, to make they templates and so on.

Loom
  • 9,768
  • 22
  • 60
  • 112
  • You might want to reconsider your design. Circular dependencies should be avoided whenever possible. – David Rodríguez - dribeas Sep 13 '13 at 12:49
  • I guess it is an interesting theoretical problem itself. And actually, I believe circular reference between classes has right to exist. Have a look at this [answer](http://stackoverflow.com/a/1899351/723845). – Loom Sep 13 '13 at 13:37
  • When you create a circular dependency with references you are effectively stating that neither of them can live without the other. Borrowing the example from the linked question: a person cannot exist without a pet, and a pet cannot exist without an owner. I am not saying that there is no design in which this could make sense, just stating that in most cases this is not what you want. – David Rodríguez - dribeas Sep 13 '13 at 13:47
  • `const` added due to the fact that bunch of `foo`es and `bar`s are loaded from file at the service startup. So, relations between them are unchangeable. It is desirable to ensure that anything cannot change them – Loom Sep 13 '13 at 14:15

2 Answers2

6

What is the linkage of foo and bar? If they have external linkage, you can write something like:

extern Foo foo;
extern Bar bar;

Foo foo( bar );
Bar bar( foo );

(I'm assuming here that it is the constructors which set the reference to a parameter.)

This supposes namespace scope and static lifetime, of course (but an anonymous namespace is fine).

If they are class members, there's no problem either:

class Together
{
    Foo foo;
    Bar bar;
public:
    Together() : foo( bar ), bar( foo ) {}
};

If they're local variables (no binding), I don't think there's a solution.

EDIT:

Actually, the local variables have a simple solution: just define a local class which has them as members, and use it.

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • 1
    "I don't think there's a solution" that doesn't involve in-place `new` and possibly UB (like `aligned_storage::type f_; Foo& f = reinterpret_cast(f_); Bar b(f); new(&f) Foo(b);`) – dyp Sep 13 '13 at 11:31
  • In any of these solutions, using the references in the ctor might invoke UB. – dyp Sep 13 '13 at 11:34
  • @DyP I thought of that. But I didn't think of using the references to make it transparent once the initialization had finished. Similarly, there should be some solution involving `union`, now that you can put non-trivial classes in a `union`. – James Kanze Sep 13 '13 at 11:34
  • I think `union` would have to be UB as only one member may be active at a time. – dyp Sep 13 '13 at 11:35
  • @DyP That goes without saying. _Any_ use of the reference (other than taking its address or using it to initialize another reference) will result in undefined behavior until the referenced object is fully constructed. – James Kanze Sep 13 '13 at 11:36
  • 1
    @DyP But calling a member function which constructs the class member makes that member active. And you can take a reference to an inactive member, as long as you don't try to do anything with it except take its address or use it to initialize another reference. – James Kanze Sep 13 '13 at 11:37
  • What about `std::pair x = {{x.second}, {x.first}};`? – dyp Sep 13 '13 at 11:40
  • @DyP Excellent. Except that the names for the members aren't really intuitive. I'd rather have a class calling them `foo` and `bar`. (For that matter, it doesn't even have to have a constructor. If it's an aggregate, aggregate initialization can be used.) – James Kanze Sep 13 '13 at 12:43
0

This can't work if i understand your Problem correctly, since to create an Object Bar you need Foo and vice versa. You must not use References but an Pointer instead. Where you can create both Objects separatley and then set Bar to Foo and Foo to Bar.

class Foo
{ 
public:
   Foo();
   void setBar( const Bar* bar ){ _bar = bar; }

private:
   const Bar* _bar;
}
// class Bar analog to Foo


void xxx:something(void)
{
   Foo* f = new Foo;
   Bar* b = nee Bar;
   f->setBar(b);
   b->setBar(f);
   ...
}
Teh Suu
  • 1,759
  • 1
  • 11
  • 7