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添加到类中,这使您为不使用(或可能不使用)的内容付费