对于这个问题,假设以下代码流:
void * some_data = allocate_memory(const std::string & type)
fetch_data_from_somewhere(some_data);
send_data_to_client(some_data);
allocate_memory
只会分配一个空消息,该消息将通过fetch_data_from_somewhere
填充(包括可能的动态内存分配),然后由send_data_to_client
发送到某个地方。然后,客户端将数据转换为实型(只有他知道)。
我现在必须给函数写allocate_memory
,只给出一个标识类型的字符串。有了这些信息,我可以获得描述消息的数据结构(例如:它长80个字节,前4个字节中有一个整数,其后是std :: vector等)。
假设我知道我必须分配一个std::vector<T>
,其中T
是我不知道的类型(同样,我知道该类型的字符串标识符,并且可以访问有关其结构,大小,等)。
如果我使用void * some_memory = calloc(sizeof(std::vector<T>), 1)
,这似乎适用于gcc,clang和MSVC ++编译器的所有T
(布尔值除外)。稍后,客户端可以执行static_cast<std::vector<T>>(some_memory)
,并且使用所有矢量操作似乎都可以工作。这似乎有些合理,尽管我无法确定它是否可以保证正常工作。
但是,如果我想传递自己的分配器,在我看来我很走运:我希望零分配的内存无法工作,但是我不能真正做到{{1 }}或类似的名称,因为我不知道void * = new std::vector<T, MyAllocator>(0, my_allocator)
。如果我需要一个T
类型的向量,则我认为可以使用std::vector<T *>
,因为无论如何在内存中都没有类型化数据。
有什么方法可以在编译时(跨平台...)分配具有未知类型std::vecotr<void *>
的{{1}}?
这显然不是预定用途,也不是干净的代码,但是出于问题的考虑,让我们假设我对此无能为力。
答案 0 :(得分:3)
仅仅分配一堆内存并不是向量make。您的calloc
解决方案是错误的,因为它实际上并未构造向量,而且您将构造其中的内存没有正确对齐。您反复观察到此方法“有效”的事实纯属不幸。从理论上和实践上,您都可以期望它会灾难性地爆炸。
即使您需要做的只是分配一些内存,您仍然无法使用未知类型的向量来完成此操作,因为您不知道vector<unknown-type>
的大小。当然,您无法构建一个。甚至您的vector<T*>
→vector<void*>
想法都不起作用:您忘记了每个vector
专长都是完全不同的类型,并且值类型之间的关系不会在结果容器之间创建关系类型。
您的方法过于幼稚,无法总体上成功生成C ++对象。 C ++使我们operator new
和分配器协调工作是有原因的。仅仅提供“内存,使用内存”的C风格是不够的。然后您想要“将数据发送到客户端”的事实也是一个危险信号:您无法通过将复杂的C ++对象转储到网络中来直接序列化它们。
最后,我的强制性警告是C ++是一种抽象,并且,如果您尝试编写在字节级别上操作对象的“聪明”源代码,则需要非常小心。 C ++希望您在创建对象时从字面上告诉它,而在要销毁该对象时从字面上告诉它。否则,假装该对象存在很容易产生奇怪的现象,因为编译器(包括但不限于在其优化阶段)充分利用了构成该语言的复杂且语义繁多的规则。通常,您确实确实需要“说明您的意思”,而不是试图落后。 (存在一些对此规则的有限例外,主要是围绕内置类型对象的宽大处理,以及使用char*
为现有的,正确构造的对象加上别名的能力;这些例外均不适用于您的要求。)>
粘贴提供的构建/分配工具,并编写序列化程序。