【问题标题】:Is it a good practice to use a vector of bytes as raw storage for other types?使用字节向量作为其他类型的原始存储是一种好习惯吗?
【发布时间】:2019-01-12 01:10:09
【问题描述】:

我已经开始关注 YouTube 上的 ECS 教程,之前我从未见过有人将新变量分配到 vectoruint8 中。

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

(有问题的完整代码可以在here找到;Array这里是#define Array std::vector

它与使用指针向量有何不同,为什么更好?

【问题讨论】:

  • 池分配器的特定实现似乎完全忽略了对齐约束,这对 x86 上的性能不利,并导致在不太宽容的平台上崩溃(就标准而言,它是未定义的行为)。
  • 顺便说一句,你真的应该在你的问题中包含相关代码以使它们自包含,github repos来来去去......
  • 池分配器对我来说是新的,但它看起来很有趣。正如@john-zwinck 指出这种分配策略一样,我已经开始了解更多有关它的信息。感谢您对 Github 的建议。

标签: c++ memory vector entity-component-system


【解决方案1】:

这基本上是一个“池分配器”。既然您知道它叫什么,您就可以了解它为什么这样做了,但性能通常是动机。

所有分配都在一个向量中完成,最后整个向量可以立即释放(在销毁其中的对象后,您可以在下面的释放函数中看到)。

【讨论】:

    【解决方案2】:

    使用vector 字节对我来说有两个问题:

    1. 对齐。尽管您可以使用对齐的分配器来解决这个问题。如果您在运行前不知道预先存储了哪些类型以及它们的对齐要求,那么稍微浪费一点(但对于少数大型容器来说不是那么多)只是为动态分配使用最大对齐。
    2. 这是我书中更大的问题,这与向量在向其插入元素时如何重新分配其数组有关。如果您在其中存储非平凡的构造/可破坏类型,则可能会通过在内存中复制它们的字节而不正确调用必要的移动/复制ctors和dtors而造成严重破坏。

    如果您想让您的 ECS 将全新的组件类型连续存储在内存中,那么我推荐的一种危险性较小的方法是抽象您的组件容器,如下所示:

    struct Components
    {
         virtual ~Components() {}
    };
    
    template <class T>
    struct ComponentsT: public Components
    {
         std::vector<T> components;
    };
    

    当你想向系统注册一个新的组件类型Foo,你可以动态分配和实例化ComponentsT&lt;Foo&gt;,把它粘在一个多态容器(容器的容器)中,当你想添加将Foo 组件添加到实体(因此实例化它并将其添加到组件列表中),获取相关抽象Components* 基指针/引用,将其向下转换(可以使用dynamic_cast)到ComponentsT&lt;Foo&gt;*,然后推送回到你的组件实例那里。现在您将所有Foos 连续存储在内存中,而无需处理对齐和失效等问题。

    【讨论】:

      猜你喜欢
      • 2016-06-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-20
      • 2011-03-06
      相关资源
      最近更新 更多