2013-08-22 14 views
0

我有一些(在我看来)相当具体的所有权要求:我有一个类,基本上解释一个双精度数组是一种特定的方式(一些相当大矩阵),并且希望与以另一种方式解释(一个非常长的数学向量)的C库进行通信。在某些情况下,我想解释一个由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每个操作是可能的owning- Foo,另外,owning- Foo可以自由复制和移动。它闻起来像Liskov替代原则是满意的。能够以相同的方式处理拥有 - FooFoo句法上没有编写一组方法拥有 - Foo委托给一个成员变量非常舒服舒适

另一方面,可能会有所有者 - Foo,而不是处理所有权,而是包含可从外部访问的Foo实例,从而更好地分离关注点。

我实现owning- 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之前initilized

+0

这是相当复杂和难以遵循恕我直导。我认为你需要保持简单。核心问题是,有时候你的代码拥有数据,有时候它是由某个外部库拥有的,对吗?那么,如何在Foo中标记一个关于谁是所有者的标志,并且析构函数会查看标志并适当地删除(或不)。 –

+0

嗯,我不认为这可行。拥有的'Foo'(或者''Foo''的拥有者)是可移动的或可复制的,而我认为非拥有的''Foo'不应该是这样,以免它超过它不拥有的缓冲区。由于事实上我的代码已经因*数学*原因而混淆(即它是一个非平凡数学模型的实现),我想在编译时检查尽可能多的正确性,因为它实际上是可能的。 –

+1

如果您想在编译时检查数学正确性,请使用函数式语言。 C语言是为编写操作系统的明确目的而发明的,C++尽管增加了许多像OOP这样的花哨的东西,但非常遵循相同的设计原则。如果你在做数学,使用一种非常适合数学的语言,比如Haskell或者Scala。您可能会失去一些运行时间性能,但您可以获得开发时间效率和编译时正确性检查。 –

回答

1

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

真的,你应该有一个可能共享的缓冲区,以便跟踪所有权。将它隐含地编程为“不是我”,知道发生了什么的其他地方是相当脆弱的。

“检查所有权标志”仅仅是“我是最后/唯一所有者”的特例,它有一个可以使用的通用强大实施。

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

+0

在我遇到的问题中,我想避免对C库(实际上是通过'extern“C”'引用的FORTRAN库)进行任何修改。虽然我确实有(开放)源代码,但图书馆做了我不熟悉并且害怕破坏的数字优化内容。但是,我的问题相当老旧,在更快乐的情况下,您的方法更可取,所以我将其标记为已接受。 –

+1

谢谢。 “这是真实的,但往往不会教到现实生活中需要的程度,人们必须处理这样的问题。 C++在内存和接口方面能做“任何你想要的”几乎是独一无二的,所以它非常适合这样的任务。 –