2

我的情况类似于包括:

class A
{
    public:
        A(shared_ptr<B>);
}

class B : public enable_shared_from_this<B>
{
    const shared_ptr<A> a;
}

我不能shared_ptrB构造之前,所以之前a被初始化。所以,我需要在构造后初始化我的常量字段(我认为它拒绝 RAII),或者只是稍后再构造它(所以它不能是 const,所以它否认 const 正确性,并且看起来也不太一致RAII)。

这看起来很常见。有没有最干净的方法来处理这个?你会怎么做?

4

3 回答 3

2

我会通过没有const成员来解决这个问题,简单明了。它们通常比它们的价值要麻烦得多(例如,它们使类不可分配,甚至不能移动分配)。

a是私有的,所以只有类本身可以访问它。因此,记录“a在初始化后永远不应该修改!!!”就足够了。如果您担心这还不够(或者该课程friend超出了您的控制范围),您可以使这一点更加明显,如下所示:

class B : public enable_shared_from_this<B>
{
  const std::shared_ptr<A>& a() { return _use_this_ONLY_for_initialising_a; }

  std::shared_ptr<A> _use_this_ONLY_for_initialising_a;
};
于 2014-04-29T07:22:00.977 回答
2

这种情况是重构代码的一个很好的指标。在找到解决此问题的方法之前,请考虑是否B应该真正继承A或成为其中的一员......A

.. 因为它可能会删除你的对象的 constness - 并且可能不使用 shared_ptr (你在那里有一个循环引用,所以单独的引用计数永远无法破坏你的对象!)。

于 2014-04-29T07:29:00.357 回答
0

如果A实际上并没有保留shared_ptr<B>您传递的副本(只是B简单地使用),那么您可以进行这项工作(见下文),但是:

  1. 如果A不保留对 the 的引用,B则它可能只需要一个B&orB*参数,而不是 a shared_ptr<B>,因此您应该更改设计。
  2. 如果A确实保留了引用,那么您将获得循环引用,因此您应该更改设计。

这行得通,但确实非常可怕,并且很容易引入错误,而且通常是一个坏主意,我可能什至不应该展示它,只需更改您的设计以避免循环依赖:

#include <memory>
#include <iostream>

class B;

class A
{
public:
  A(std::shared_ptr<B> b);
};


class B : public std::enable_shared_from_this<B>
{

  // return a shared_ptr<B> that owns `this` but with a
  // null deleter. This does not share ownership with
  // the result of shared_from_this(), but is usable
  // in the B::B constructor.
  std::shared_ptr<B> non_owning_shared_from_this()
  {
    struct null_deleter {
      void operator()(void*) const { }
    };

    return std::shared_ptr<B>(this, null_deleter());
  }

public:
  B(int id)
  : m_id(id), a(std::make_shared<A>(non_owning_shared_from_this()))
  { }

  int id() const { return m_id; }

private:
  int m_id;
  const std::shared_ptr<A> a;
};

A::A(std::shared_ptr<B> b)
{
  std::cout << b->id() << std::endl;
}

int main()
{
  auto b = std::make_shared<B>(42);
}
于 2014-04-29T18:34:57.857 回答