使用字节向量作为其他类型的原始存储是一种好的做法吗
Is it a good practice to use a vector of bytes as raw storage for other types?
我开始在YouTube上学习ECS教程,以前从未见过有人将新变量分配到uint8
的vector
中。
template<typename Component>
uint32 ECSComponentCreate(Array<uint8>& memory, EntityHandle entity, BaseECSComponent* comp)
{
uint32 index = memory.size();
memory.resize(index+Component::SIZE);
Component* component = new(&memory[index])Component(*(Component*)comp);
component->entity = entity;
return index;
}
(有问题的完整代码可以在这里找到;这里的Array
是#define Array std::vector
(
它与使用指针向量有什么不同,为什么它更好?
这基本上是一个"池分配器"。既然你知道了它的名字,你就可以了解它为什么这么做了,但性能通常是动机。
所有的分配都是在一个向量中完成的,最后整个向量可以立即解除分配(在销毁其中的对象之后,您可以在下面的解除分配函数中看到(。
使用vector
字节对我来说有两个问题:
- 对齐。尽管您可以通过一个对齐的分配器来解决这个问题。如果您在运行时之前还不知道要提前存储哪些类型及其对齐要求,那么稍微浪费一点(但对于少数大型容器来说就不那么浪费了(就是对动态分配使用最大对齐
- 在我的书中,这是一个更大的难题,这与在向vector插入元素时vector如何重新分配其数组有关。如果你在其中存储非平凡的构造性/可破坏性类型,那么在没有正确调用必要的移动/复制器和dtor的情况下,在内存中复制它们的字节可能会造成严重破坏
如果你想让你的ECS在内存中连续存储全新的组件类型,那么我建议一种危险性小得多的方法是抽象你的组件容器,比如:
struct Components
{
virtual ~Components() {}
};
template <class T>
struct ComponentsT: public Components
{
std::vector<T> components;
};
当你想向系统注册一个新的组件类型Foo
时,你可以动态分配和实例化ComponentsT<Foo>
,将其粘贴在多态容器(容器的容器(中,当你想将Foo
组件添加到实体中时(因此实例化它并将其添加到组件列表中(,获取相关的抽象Components*
基指针/ref,将其下变频(可以使用dynamic_cast
(到ComponentsT<Foo>*
,然后将您的组件实例推回到那里。现在,您可以将所有的Foos
连续存储在内存中,而无需处理对齐和无效等问题。
相关文章:
- 将相同共享指针的副本存储在不同的向量中是否是一种好的做法?
- 使用类在C++中存储和列出变量/方法是否是一种好的做法
- 有没有一种惯用的方法可以在不存储变换或不必要地重新计算的情况下找到数组变换的最小/最大值?
- 使用字节向量作为其他类型的原始存储是一种好的做法吗
- 如何将 numpy 二维数组作为一种可以用C++读取的二进制格式存储在磁盘上
- 存储多种颜色并从一种颜色切换到另一种颜色
- 是否有一种方法可以访问/解除并找到存储在双指针向量中的元素的值
- 是否有一种方法可以从文本文件中读取并将单个数据存储为不同的变量
- 是否有一种方法在C 中使用libgit2在远程存储库上进行计数
- 在动态分配时,在免费存储上指向一个新地址是一种好的做法吗
- 有没有一种方法可以防止以前运行的值存储在txt文件中(防止覆盖)
- 有没有一种方法可以将阈值运算输出存储在Eigen(C++)中
- 是 2s 补码存储负数的一种方式
- 将多种类型的 lambda 函数存储在一种类型的变量中
- 有没有一种方法可以在容器中存储不同的函数指针类型?
- 有没有一种方法来存储日期和时间的结构?c++
- 将一种类型的STL对象存储到另一种类型的有效方法
- 是否有一种方法可以改变变量在内存中的存储方式(位大小)
- 将不同的对象存储为一种对象类型(c++)
- 有没有一种方法可以在输出二进制文件中存储clang编译时标志