C++ 将C对象数组包装到C++;班

C++ 将C对象数组包装到C++;班,c++,c++11,C++,C++11,我的C库中有这样的API: extern "C" { typedef struct Opaque Opaque; Opaque *foo_new(); void foo_delete(Opaque *); int foo_f(Opaque *, int); } 为了简化其使用,我将其包装为: class Foo final { public: Foo() { self_ = foo_new(); } ~Foo() { foo_delete(se

我的
C
库中有这样的API:

extern "C" {
    typedef struct Opaque Opaque;

    Opaque *foo_new();
    void foo_delete(Opaque *);
    int foo_f(Opaque *, int);
}
为了简化其使用,我将其包装为:

class Foo final {
public:
    Foo() { self_ = foo_new(); }
    ~Foo() { foo_delete(self_); }
    //code for copy/move constructor and operator=
    int f(int a) { return foo_f(self_, a); }
private:
    Opaque *self_;
};
很好,但是我必须包装这个不透明对象的数组:

extern "C" {
    typedef struct OpaqueArray OpaqueArray;

    OpaqueArray *calc_foo_array();
    void foo_array_delete(OpaqueArray *);
    Opaque *foo_array_elem(OpaqueArray *, size_t i);
}
所以我需要实现
类FooArray

class FooArray final {
public:
    ??? operator[](const size_t i) {
       auto obj = foo_array_elem(self_, i);
       ???
    }
private:
    OpaqueArray *self_;
};
但是,作为
操作符[]
的结果,我应该返回什么

我可以从
不透明*
创建
Foo
,但是
Foo::~Foo()
是数组的自由部分, 怎么了?我可以创建与
Foo
完全相同的
FooRef
, 但是不要调用
foo\u delete
,但实际上我有几个这样的
C类
, 我宁愿不要创建这么多重复的代码。 也许我可以用
reinterpret\u cast
,因为
sizeof(Foo)=sizeof(不透明*)
并从
operator[]
返回
Foo&
,但是
Foo&
实际上是
不透明的**
, 所以我需要在某个地方保持
不透明
,使其地址稳定


可能有一些标准的解决方案可以解决这类问题吗?

您可以修改您的Foo类,使其能够保存它不拥有的指针

class Foo
{
    public:
        Foo()
        {
            self_ = foo_new();
            m_owned = true;
        }

        Foo(Opaque *pOpaque) 
        { 
            self_ = foo_new(); 
            m_owned = false;
        }

        ~Foo()
        {
            if (m_owned) foo_delete(self_);
        }

        //code for copy/move constructor and operator=
        int f(int a) { return foo_f(self_, a); }

    private:
        bool m_owned;
        Opaque *self_;
};


class FooArray
{
    public:
        Foo operator[](const size_t i)
        {
           return Foo(foo_array_elem(self_, i));
        }

    private:
        OpaqueArray *self_;
};

我会用你建议的
FooRef
来做,但有点不同:

class FooRef {
public:
    FooRef (Opaque *o) { self_ = o; }
    int f(int a) { return foo_f(self_, a); }
protected:
    Opaque *self_;
};


class Foo : public FooRef {
public:
    Foo() { self_ = foo_new(); }
    //code for copy/move constructor and operator=
    ~Foo () { foo_delete(self_); }
};
此解决方案避免了代码重复,并允许您安全地从阵列返回Foo。顺便说一下,您可以通过
Foo
简单地创建
FooRef
。现在,您只需执行以下操作:

class FooArray final {
public:
    FooRef operator[](const size_t i) {
       return FooRef(foo_array_elem(self_, i));
    }
private:
    OpaqueArray *self_;
};

我认为这应该以一种优雅的方式完成。但是为什么运行时决策,而我知道在编译时是否应该调用
foo_delete
?我通常会编写不适合某个特定情况的代码。如果其他代码创建并删除数组中的条目,那么Foo类也删除它正在“包装”的数组中的条目是不好的。他处理这两种情况的方式(1)它创建的项目和(2)其他地方创建的项目。在接受不透明*的构造函数中,它不应该是
\u self=pOpaque
?Gian,“self”是在原始帖子中选择的命名约定,所以我保留了它。我更喜欢我自己或者甚至(更好?)m_self(我是老派),这是在有人决定放弃“m”(m=member)之前每个人都做的。你真的需要
f
成为成员函数吗?你可以简单地让
f
成为一个自由函数,让
operator[]
返回一个
Opaque*
,而
Foo
有一个隐式的转换操作符,转换为
Opaque*
。OT:你违反了3/5/0的规则。@manni66如果你是说复制/分配,我就跳过它们,你可以找到关于这个的代码注释。这可以通过给
FooRef
一个虚拟析构函数来改进,例如,用户可以存储一个真正指向
Foo
@aschepler部分为真的
std::unique\u ptr
。但另一方面,它将vtable添加到类中,这使您为不使用(或可能不使用)的内容付费