如果我有struct instanceData:
struct InstanceData
{
unsigned usedInstances;
unsigned allocatedInstances;
void* buffer;
Entity* entity;
std::vector<float> *vertices;
};
我为实体和std :: vector分配了足够的内存:
newData.buffer = size * (sizeof(Entity) + sizeof(std::vector<float>)); // Pseudo code
newData.entity = (Entity *)(newData.buffer);
newData.vertices = (std::vector<float> *)(newData.entity + size);
然后尝试将任意大小的矢量复制到它:
SetVertices(unsigned i, std::vector<float> vertices)
{
instanceData.vertices[i] = vertices;
}
我收到了访问冲突读取位置错误。
我已经删除了我的代码以使其简洁,但它基于Bitsquid's ECS。所以如果我不处理向量(它确实如此),那么就假设它有效。考虑到这一点,我假设它有问题,因为它不知道矢量将扩展到什么尺寸。但是,我认为向量可能会沿着另一个维度增加,像这样?:
我错了吗?无论哪种方式,如何在缓冲区中为矢量分配内存?
是的,I know vectors manage their own memory。除此之外,还有。我试图做一些不同的事情。
答案 0 :(得分:3)
看起来您希望InstanceData.buffer拥有由其他东西分配/取消分配/访问的实际内存空间。然后实体和顶点指针指向此空间。但是通过尝试使用std :: vector,你混合了两种完全不兼容的方法。
1)您可以使用语言和标准库执行此操作,这意味着没有原始指针,没有“新”,没有“sizeof”。
struct Point {float x; float y;} // usually this is int, not float
struct InstanceData {
Entity entity;
std::vector<Point> vertices;
}
这是我推荐的方式。如果需要输出特定的二进制格式进行序列化,只需在save方法中处理它。
2)您可以使用oldschool C管理类内部的内存,这意味着对顶点使用N * sizeof(float)。由于这对于新程序员而言极其容易出错(并且对于兽医来说仍然很粗糙),因此必须将所有这些都设置为InstanceData类,并且不允许InstanceData之外的任何代码来管理它们。使用单元测试。提供公共getter功能。对于通过网络的数据结构,或者在读取/写入具有指定格式的文件(Tiff,pgp,z39.50)时,我已经完成了这样的事情。但只是使用困难的数据结构存储在内存中 - 没办法。
您提出的其他一些问题:
如何为std :: vector分配内存?
你没有。向量分配自己的内存并进行管理。您可以告诉它resize()或reserve()空间或push_back,但它会处理它。看http://en.cppreference.com/w/cpp/container/vector
如何在这样的缓冲区中为矢量[sic]分配内存?
你似乎在考虑一个数组。到目前为止你已经离开了伪代码,所以你真的需要通过一个教程来解决问题。你必须用“新”分配。如果你真的需要,我可以为此发布一些入门代码,我会在这里编辑答案。
另外,你说过一些关于向量增加的东西。向量是一维的。你可以制作一个向量的向量,但是我们不能进入那个。
编辑附录:
使用megabuffer的基本思想是在缓冲区中分配所有必需的空间,然后初始化值,然后通过getter使用它。
数据布局是“Header,Entity1,Entity2,...,EntityN”
// I did not check this code in a compiler, sorry, need to get to work soon
MegaBuffer::MegaBuffer() {AllocateBuffer(0);}
MegaBuffer::~MegaBuffer() {ReleaseBuffer();}
MegaBuffer::AllocateBuffer(size_t size /*, whatever is needed for the header*/){
if (nullptr!=buffer)
ReleaseBuffer();
size_t total_bytes = sizeof(Header) + count * sizeof(Entity)
buffer = new unsigned char [total_bytes];
header = buffer;
// need to set up the header
header->count = 0;
header->allocated = size;
// set up internal pointer
entity = buffer + sizeof(Header);
}
MegaBuffer::ReleaseBuffer(){
delete [] buffer;
}
Entity* MegaBuffer::operator[](int n) {return entity[n];}
标题始终是固定大小,只显示一次,并告诉您有多少实体。在你的情况下,没有标题,因为你正在使用成员变量“usedInstances”和“assignednstances”。所以你有一个标题,但它不是分配缓冲区的一部分。但是你不想分配0个字节,所以只需设置usedInstances = 0; allocatedInstances = 0;缓冲液= nullptr;
我没有改变缓冲区大小的代码,因为bitsquid ECS示例涵盖了这一点,但他没有显示第一次初始化。确保初始化n和已分配,并在使用之前为每个实体分配有意义的值。
您没有像您发布的链接那样使用比特币ECS。在那里,他在并行数组中有几个固定大小的不同对象。有一个实体,它的质量,它的位置等。所以实体[4]是一个质量等于“质量[4]”的实体,它的加速度是“加速度[4]”。这使用指针算法来访问数组元素。 (内置数组,NOT std :: Array,NOT std :: vector)
数据布局是“Entity1,Entity2,...,EntityN,mass1,mass2,...,massN,position1,position2,...,positionN,velocity1 ......”你明白了。
如果您阅读了这篇文章,您会发现他说的基本上与其他人所说的标准库相同。您可以使用std容器来存储这些数组中的每一个,或者您可以分配一个megabuffer并使用指针和“内置数组”数学来获取每个项目的缓冲区内的确切内存位置。在经典的faux-pas中,他甚至说“这避免了Array类中可能存在的任何隐藏的开销,我们只有一个分配来跟踪。”但是你不知道它是否比std :: Array更快或更慢,并且你引入了很多错误和额外的开发时间来处理原始指针。
答案 1 :(得分:1)
我想我明白你要做什么了。
有很多问题。第一。你正在制作随机数据的缓冲区,告诉C ++它的Vector大小是一个Vector。但是,您实际上没有将构造函数调用到Vector,它会将指针和构造内部初始化为可行值。
这已在此处得到解答:Call a constructor on a already allocated memory
第二个问题是
行instanceData.vertices[i] = vertices;
instanceData.vertices是一个指向Vector的指针,所以你实际上需要编写
(*(instanceData.vertices))[i]
第三个问题是*(instanceData.vertices)的内容是浮点数,而不是Vector,所以你不应该在那里进行赋值。