【问题标题】:How can I keep const-correctness and RAII?如何保持 const 正确性和 RAII?
【发布时间】:2014-04-29 07:15:44
【问题描述】:

我有类似的情况:

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)。

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

【问题讨论】:

  • 这就是我不广泛使用 std::shared_ptr 的原因。
  • 为什么有一个 const 成员?
  • 恕我直言,AB 之间的循环依赖关系表明应该有另一种解决方案,这两种类型之间的耦合较少。
  • @Nobody 对,A 应该在构造函数中获取 weak_ptr,我忘记了循环。我从智能指针开始。
  • 我什至不谈论智能指针,我认为std::weak_ptr 不会解决我正在谈论的问题:看起来错误的代码依赖关系。在没有看到实际代码的情况下,我对此无话可说。

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


【解决方案1】:

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

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

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

    • A 绝对不应该继承。 A 是一些与B 密切相关的小组件,我将其分发到GUI 的某些部分以分离界面。我想我会放弃const,使用getter 来访问字段(在我的代码中apublic)和工厂来构建对象(与RAII 一致)。关于循环依赖——我认为A应该取weak_ptr,这是我的错误。
    【解决方案3】:

    如果A 实际上并没有保留shared_ptr&lt;B&gt; 的副本,您传递它(只是简单地使用B),那么您可以完成这项工作(见下文),但是:

    1. 如果A 没有保留对B 的引用,那么它可以只使用B&amp;B* 参数,而不是shared_ptr&lt;B&gt;,因此您应该更改设计。
    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);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-03
      相关资源
      最近更新 更多