使用C ++继承来增强具有所有权语义的类

时间:2013-08-22 15:18:00

标签: c++ oop multiple-inheritance unique-ptr liskov-substitution-principle

我有一些(在我看来)相当具体的所有权要求:我有一个基本上解释一个双精度数组的类是一种特定的方式(一些相当大的矩阵的串联),并希望与一个C库进行通信然后以另一种方式解释(一个非常长的数学向量)。在某些情况下,我想解释一个由C库传递给回调的指针,即没有取得所有权。在这种情况下,复制将是非常不切实际的。在其他情况下,我想自己分配缓冲区,并自己将其传递给C库。在这种情况下,我的代码拥有缓冲区。

我创建了一个“构建块”,它将双数组解释为矩阵(使用boost::numeric::ublas::shallow_array_adaptor,但这几乎无关紧要),如下所示:

class Foo {
 public:
  explicit Foo(double *buffer);
  Foo(const Foo &) = delete;
  Foo(Foo &&) = delete;
  Foo &operator=(const Foo &) = delete;
  /* Some accessors. */
 protected:
  Foo &operator=(Foo &&) = default;
 private:
  /* Some things that store pointers into the buffer. */
};

禁止复制和移动,以便不会意外地创建或移动一个比缓冲区本身更长的地方。当然,通过直接将指针传递到某处可以有意识地创建这样的实例,但是可以在源代码中更容易地发现它。

我的问题的第一部分:让“Foo增强了缓冲区的所有权”是Foo的子类是否有意义?

Foo的所有操作都可以通过拥有 - Foo,另外,拥有 - Foo可以自由复制和移动。它闻起来像Liskov替代原则是满意的。能够以同样的方式处理拥有 - FooFoo而无需在拥有一堆方法中编写 - Foo委托给成员变量非常舒适

另一方面,可能会有所有者 - Foo来处理所有权而不处理任何其他内容,并且包含可以从外部访问的Foo实例,从而提供更好的服务关注点分离。

我实现了拥有 - Foo这样:

class OwningFoo : private std::unique_ptr<double[]>, public Foo {
 public:
  explicit OwningFoo(std::size_t size)
      : std::unique_ptr<double[]>(new double[size]),
        Foo(std::unique_ptr<double[]>::get()), size_(size) {
  }
  /* Implementation of copy and move constructors and
   * assignment operators redacted. */
  OwningFoo(const OwningFoo &);
  OwningFoo(OwningFoo &&);
  OwningFoo &operator=(const OwningFoo &);
  OwningFoo &operator=(OwningFoo &&);
 private:
  std::size_t size_;
};

我的第二部分问题:这是多重和私有继承的好例子吗?我在某个地方拍摄自己的脚吗?

请注意,如果Foo不是成员,则std::unique_ptr不能成为成员,因为它需要在 Foo之前启动。

1 个答案:

答案 0 :(得分:1)

我这样做的方法是将所有权问题推向更远的地方。 Foo有一个缓冲区,并知道如何在销毁时清理缓冲区。例如,std :: shared_ptr有一个可用于此目的的destroy回调。这显示了智能指针知道如何删除此特定实例的已接受模式。

实际上,您应该有一个可能的共享缓冲区,以便跟踪总拥有量。隐含地将它编程为“不是我”与其他地方知道发生了什么是相当脆弱的。

“检查所有权标志”只是“我是最后一个/唯一所有者”的特例,它具有您可以使用的一般强大实现。

在你提到的扭曲中,拥有缓冲区的C代码如何与你的类的生命周期协调?这听起来很糟糕,让你的班级知道它不拥有缓冲区(以一种封装良好的方式)不会改变C代码的问题,因为它不知道你的实例何时完成它。