如何初始化具有循环引用的const成员变量

6
例如,我有两个类。
class Foo;
class Bar;

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

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

foo成为Foo的对象,bar成为Bar的对象。是否有任何方法(正常或“黑客”)可以创建/初始化foobar,使它们的成员m_barm_foo相互引用(我的意思是foo.m_barbarbar.m_foo 是 'foo')?
允许添加任何成员到FooBar,添加它们的父级,使它们成为模板等。

你可能需要重新考虑你的设计。尽可能避免循环依赖。 - David Rodríguez - dribeas
我想这本身就是一个有趣的理论问题。实际上,我相信类之间的循环引用是存在的。看看这个答案 - Loom
当您使用引用创建循环依赖关系时,实际上是在声明它们两者都无法独立存在。借用链接问题中的例子:一个人不能没有宠物,宠物也不能没有主人。我并不是说这种设计没有意义,只是在大多数情况下这不是您想要的。 - David Rodríguez - dribeas
由于在服务启动时从文件加载了大量的“foo”和“bar”,因此添加了“const”。因此,它们之间的关系是不可改变的。希望确保任何事物都不能改变它们。 - Loom
2个回答

6
什么是foobar的联系?如果它们具有外部链接,您可以这样写:
extern Foo foo;
extern Bar bar;

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

(我在这里假设是构造函数设置参数的引用。)
当然,这假定了命名空间作用域和静态生存期(但匿名命名空间也可以)。
如果它们是类成员,也没有问题:
class Together
{
    Foo foo;
    Bar bar;
public:
    Together() : foo( bar ), bar( foo ) {}
};

如果它们是局部变量(没有绑定),我认为没有解决方法。
编辑:
实际上,局部变量有一个简单的解决方案:只需要定义一个具有其成员的本地类,并使用它。

1
我认为没有不涉及原地 new 和可能导致未定义行为的解决方案(例如 aligned_storage<sizeof(Foo)>::type f_; Foo& f = reinterpret_cast<Foo&>(f_); Bar b(f); new(&f) Foo(b);)。 - dyp
在这些解决方案中,使用构造函数中的引用可能会引发未定义行为。 - dyp
我认为union会成为未定义行为,因为一次只能有一个成员处于活动状态。 - dyp
@DyP 这是不言而喻的。除了取地址或用它来初始化另一个引用之外,任何对该引用的使用都会导致未定义的行为,直到所引用的对象完全构造出来。 - James Kanze
1
@DyP 但是调用构造类成员的成员函数会使该成员变为活动状态。只要您不尝试对其进行任何操作,除了获取其地址或使用它来初始化另一个引用,您就可以引用非活动成员。 - James Kanze
显示剩余3条评论

0

如果我正确理解您的问题,这是行不通的,因为要创建一个对象Bar,您需要Foo,反之亦然。您不能使用引用,而应该使用指针。在这种情况下,您可以分别创建两个对象,然后将Bar设置为Foo,将Foo设置为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);
   ...
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接