101*_*010 2 c c++ pointers void-pointers
我正在尝试将C++类(例如class foo)与C 接口.到目前为止,我所做的是定义一个C结构,它包含一个不透明的指针成员变量(即void*),指向相关的C++ foo对象.
struct C_foo {
void *foo_obj;
};
Run Code Online (Sandbox Code Playgroud)
我定义了一个alloc()C接口函数来分配类型的对象C_foo:
struct C_foo* alloc(/* input */) {
struct C_foo *out = new struct C_foo;
out->foo_obj = new foo(/* input */);
return out;
};
Run Code Online (Sandbox Code Playgroud)
我现在要做的是创建一个dealloc()C接口函数,该函数将正确释放C_foo先前分配的类型的对象,如上alloc()所示:
void dealloc(struct C_foo *obj) {
/* ??? */
}
Run Code Online (Sandbox Code Playgroud)
我知道显式删除void*指针(即delete obj->foo_obj;)会导致未定义的行为(§5.3.5/ 1 [expr.delete]):
该
delete-expression的结果的类型为void[81].[81]这意味着无法使用类型指针删除对象, 因为它不是对象类型.
void*void
我将如何正确解除struct C_foo对象的释放?
Mik*_*our 12
如果你知道(肯定)它指向什么类型,那么施放:
delete static_cast<foo*>(obj->foo_obj);
Run Code Online (Sandbox Code Playgroud)
如果你忘记了类型,那么你需要重新设计.
如果由于某些C API而需要传递不透明的句柄,并且对象具有完全不同的类型,则可以使用下面概述的方法。
请注意,如果所有类型都共享一个公共base,则可以只为base提供一个虚拟析构函数,static_cast即void*指向base的指针delete。这是一种比我在下面概述的方法更为普遍的方法。
这将需要持有一个指向分配的对象yuo的指针,以及一个指向对该类型进行编码的对象的指针(以便您可以将其删除):
struct Handle {
void* handle;
void* deleter_info;
};
Run Code Online (Sandbox Code Playgroud)
您将有一些课程。这些就是您想要传递给...实例的句柄的东西。
class Foo;
class Bar;
// etc
Run Code Online (Sandbox Code Playgroud)
您还需要删除器的基类:
struct deleter_base {
virtual void destroy(Handle h) = 0;
virtual ~deleter_base() {}
};
Run Code Online (Sandbox Code Playgroud)
...和一个类模板,以产生知道相关类型的派生类:
template<typename T> struct deleter {
virtual void destroy(Handle h)
{
T* ptr = static_cast<T*>(h.handle);
delete ptr;
}
};
Run Code Online (Sandbox Code Playgroud)
对于要提供其句柄的每种类型,您都需要一个函数来创建一个句柄:
Handle create_foo_handle()
{
Handle h = {0};
h.ptr = new foo;
h.deleter_info = new deleter<foo>;
return h;
}
Handle create_bar_handle()
{
Handle h = {0};
h.ptr = new bar;
h.deleter_info = new deleter<bar>;
return h;
}
Run Code Online (Sandbox Code Playgroud)
您将需要一个destroy函数:
void destroy(Handle h)
{
deleter_base* deleter = static_cast<deleter_base*>(h.deleter_info);
deleter->destroy(h); // delete the foo, or bar, or whatever
delete deleter; // delete the deleter
}
Run Code Online (Sandbox Code Playgroud)
该结构可以包含a deleter_base* deleter_info而不是void* deleter_info。这实际上是一个口味问题,以及是否要struct deleter_info;在C API中使用。将其存储在一个void*隐藏的实现细节中,使其真正变得不透明。
为了能够有意义地使用该句柄,您还需要对其他信息进行编码,以便能够从该void* handle成员中检索有用的信息。通常,变体类型使用枚举成员来执行此操作。另外,您可以希望用户足够聪明,只将其句柄传递回需要正确类型的句柄的函数。您可以使用不同的句柄结构类型(struct HandleFoo;,,struct HandleBar;...)来强制执行此操作,并且仍在void*内部使用成员来保持不透明度。