使用自定义分配器分配std :: vector并在运行时键入unknown

时间:2018-11-02 16:23:55

标签: c++ vector memory-management

对于这个问题,假设以下代码流:

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}}?

这显然不是预定用途,也不是干净的代码,但是出于问题的考虑,让我们假设我对此无能为力。

1 个答案:

答案 0 :(得分:3)

仅仅分配一堆内存并不是向量make。您的calloc解决方案是错误的,因为它实际上并未构造向量,而且您构造其中的内存没有正确对齐。您反复观察到此方法“有效”的事实纯属不幸。从理论上和实践上,您都可以期望它会灾难性地爆炸。

即使您需要做的只是分配一些内存,您仍然无法使用未知类型的向量来完成此操作,因为您不知道vector<unknown-type>的大小。当然,您无法构建一个。甚至您的vector<T*>vector<void*>想法都不起作用:您忘记了每个vector专长都是完全不同的类型,并且值类型之间的关系不会在结果容器之间创建关系类型。

您的方法过于幼稚,无法总体上成功生成C ++对象。 C ++使我们operator new和分配器协调工作是有原因的。仅仅提供“内存,使用内存”的C风格是不够的。然后您想要“将数据发送到客户端”的事实也是一个危险信号:您无法通过将复杂的C ++对象转储到网络中来直接序列化它们。

最后,我的强制性警告是C ++是一种抽象,并且,如果您尝试编写在字节级别上操作对象的“聪明”源代码,则需要非常小心。 C ++希望您在创建对象时从字面上告诉它,而在要销毁该对象时从字面上告诉它。否则,假装该对象存在很容易产生奇怪的现象,因为编译器(包括但不限于在其优化阶段)充分利用了构成该语言的复杂且语义繁多的规则。通常,您确实确实需要“说明您的意思”,而不是试图落后。 (存在一些对此规则的有限例外,主要是围绕内置类型对象的宽大处理,以及使用char*为现有的,正确构造的对象加上别名的能力;这些例外均不适用于您的要求。)

粘贴提供的构建/分配工具,并编写序列化程序。