我怎样才能保持常量和RAII?

时间:2014-04-29 07:15:45

标签: c++ c++11 shared-ptr raii weak-ptr

我的情况类似于包括:

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-correctness,并且看起来也不太一致RAII)。

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

3 个答案:

答案 0 :(得分:2)

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

a是私有的,因此只有类本身才能访问它。因此,应该足以记录&#34; a在初始化之后永远不应该被修改!!!&#34;。如果你担心自己不够(或者班级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;
};

答案 1 :(得分:2)

这种情况是重构代码的好指标。在找到解决此问题的方法之前,请考虑B是否应该实际上来自A或成为A的成员...

..因为它可能会删除你对象的常量 - 并且可能不会使用shared_ptr(你有一个循环引用,所以单独ref-counting永远不能破坏你的对象!)。 / p>

答案 2 :(得分:0)

如果A实际上没有保存您传递的shared_ptr<B>副本(只是暂时使用B),那么您可以将其工作(见下文)但是:< / p>

  1. 如果A没有引用B,那么它只能采用B&B*参数,而不是shared_ptr<B>,所以你应该改变设计。
  2. 如果A确实保留了引用,那么您将获得循环引用,因此您应该更改设计。
  3. 这很有效,但实际上非常非常糟糕,很容易引入错误,通常是一个坏主意,我可能甚至不应该显示它,只是改变你的设计以避免循环依赖:

    #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);
    }