在堆栈上分配不完整的类型
Allocate incomplete type on stack
我正在努力用 C 语言包装一个C++库。C++库是数据库服务器的库。它使用包装类来传递序列化数据。我不能直接在 C 语言中使用该类,所以我定义了一个可以在 C 代码中使用的结构,如下所示:
在include/c-wrapper/c-wrapper.h
(这是我的 C 包装器的客户端包含的包装器)
extern "C" {
typedef struct Hazelcast_Data_t Hazelcast_Data_t;
Hazelcast_Data_t *stringToData(char *str);
void freeData(Hazelcast_Data_t *d);
}
在impl.pp
extern "C" struct Hazelcast_Data_t {
hazelcast::client::serialization::pimpl::Data data; // this is the C++ class
};
Hazelcast_Data_t *stringToData(char *str) {
Data d = serializer.serialize(str);
Hazelcast_Data_t *dataStruct = new Hazelcast_Data_t();
dataStruct->data = d;
return dataStruct;
}
...
现在这行得通了,我的 C 库的客户端只能看到typedef struct Hazelcast_Data_t Hazelcast_Data_t;
.问题是,上述类型无法在堆栈上分配,就像我想提供这样的 API 一样:
// this is what I want to achieve, but Hazelcast_Data_t is an incomplete type
#include <include/c-wrapper/c-wrapper.h>
int main() {
char *str = "BLA";
Hazelcast_Data_t d;
stringToData(str, &d);
}
编译器将引发错误,指出Hazelcast_Data_t是不完整的类型。我仍然想提供一个 API,允许将堆栈分配的 Hazelcast_Data_t
引用传递给序列化函数,但由于Hazelcast_Data_t
有一个指向 C++ 类的指针,这似乎几乎是不可能的。但是,可以选择传递堆栈分配的引用将大大简化我的 C 库客户端的代码(无需释放 new
ed 结构)。
重新定义Hazelcast_Data_t
类型以便它可以在 C 中使用并且仍然可以在堆栈上分配,这是否可行?
您正在考虑执行此操作的大多数技巧都调用未定义的行为,因为 C 不会在创建结构时调用所包含对象的 C++ 构造函数,也不会在结构超出范围时调用 C++ 析构函数。要使其正常工作,您需要结构包含大小正确的缓冲区,并在 init 函数中新增该缓冲区,并在完成后在该缓冲区上调用析构函数。这意味着代码看起来像这样(假设没有任何抛出 - 在这种情况下,您需要添加异常处理和翻译......
struct wrapper {
char buffer[SIZE_OF_CXX_CLASS];
}
void wrapper_init() {
new (buffer) Wrapped();
}
void wrapper_destroy() {
((Wrapper*)buffer)->~Wrapper();
}
{
struct wrapper wrapped;
wrapper_init(&wrapped);
// ... use it ...
wrapper_destroy(&wrapped);
}
如果你忘了打电话给wrapper_init
一切都会进入不确定的behvaiour土地。如果你忘了打电话wrapper_destroy
我想你也会得到UB。
但是,由于这会迫使调用方调用 init 并销毁函数,因此使用指针几乎没有什么好处。我甚至声称,使用结构而不是指针向 API 用户表明初始化应该是微不足道的,并且不需要销毁。即作为API用户,我希望能够做到
{
struct wrapper wrapped = WRAPPER_INIT; //Trivial initialisaton macro
// .. use it ..
// No need to do anything it is a trivial object.
}
在不可能的情况下(像你一样),我会坚持通常将其分配给堆习惯用法
{
struct wrapper* wrapped = wrapper_create();
// ... use it ...
wrapper_destroy(wrapped);
}
您需要在头文件中提供结构的定义,以便客户端知道要在堆栈上分配多少空间。 但是,当C++类中的基础表示无法由extern "C"
公开时,这变得棘手。
解决方案是指向C++类而不是实际类的指针。 由于指针大小相同,因此可以在 C 客户端中使用,即使它不知道C++也是如此。
因此在标题中
typedef struct Hazelcast_Data_t {
void *data
} Hazelcast_Data_t
在C++文件中,您可以使用static_cast
通过此指针访问C++类。
创建一个包装结构,该结构仅包含一个大且对齐的数组,足以包含您的C++类型。展示位置 - 新 您的C++在其中键入。
您可能必须构建一个小的C++可执行文件,该可执行文件将生成一个具有适当定义的SIZEOF_HAZELCAST_T和ALIGNOF_HAZELCAST_T的 C 头文件。
- 拥有映射的现代方法,该映射可以指向或引用已在堆栈上分配的不同类型的数据
- 如何模板化堆栈分配的多态指针数组到接口,包括派生类型的相应点?
- 使用泛型类型推送到堆栈时出现问题
- 堆栈分配的类类型.为什么两个 ID 实例的地址相同?
- C++ 参数堆与堆栈,基元类型的数组
- 如何在C 中的标准堆栈中推动结构类型变量
- 您如何声明类型结构的堆栈?在C 中
- 返回可能在C++中分配在堆栈上的成员时,最佳指针/引用类型是什么
- 如果对象是堆栈创建的(包括继承的类型),是否可以发出编译错误
- 如何拥有一个具有多个数据类型的C++堆栈
- 表达式块类型有效 // 堆栈溢出
- 如何捕获所有类型的堆栈错误
- C++ 中的动态堆栈数据类型声明
- 堆栈/堆变量的变量/引用名称或类型存储在内存中的位置
- 无法调整类型为template的堆栈的大小
- 如何保持在堆栈上分配的对象的动态类型
- 如何创建不同类型变量的堆栈
- 析构函数如何删除嵌套堆栈类型
- 编写一个Lua包装器,如何使用可以返回多种类型的方法从堆栈返回一个值
- 在堆栈上分配不完整的类型