簡體   English   中英

如何為包含向量的數據結構分配內存?

[英]How can I allocate memory for a data structure that contains a vector?

如果我有一個struct instanceData:

struct InstanceData
{
    unsigned usedInstances;
    unsigned allocatedInstances;
    void* buffer;

    Entity* entity;
    std::vector<float> *vertices;
};

而且我為Entity和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的ECS的 因此,只要我不處理向量就假設它可以工作(確實可以)。 考慮到這一點,我假設它有問題,因為它不知道向量將縮放到多大。 但是,我認為向量可能會沿着另一個維度增加,像這樣嗎?:

在此處輸入圖片說明

我錯了嗎? 無論哪種方式, 如何在這樣的緩沖區中為矢量分配內存

是的, 我知道向量可以管理自己的內存 那不是重點。 我正在嘗試做不同的事情。

看起來您想讓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之外的任何代碼來管理它們。 使用單元測試。 提供公共獲取功能。 對於通過網絡傳輸的數據結構,或在讀取/寫入具有指定格式(Tiff,pgp,z39.50)的文件時,我已經做了類似的工作。 但是僅使用困難的數據結構存儲在內存中就沒有辦法。

您提出了其他一些問題:

如何為std :: vector分配內存?

你不知道 向量分配自己的內存,並對其進行管理。 您可以告訴它resize()或reserve()空間或push_back,但它將處理它。 看看http://en.cppreference.com/w/cpp/container/vector

我如何在這樣的緩沖區中為向量[sic]分配內存?

您似乎在考慮數組。 到目前為止,您的偽代碼還很遙遠,因此您確實需要逐步學習本教程。 您必須使用“新”進行分配。 如果您確實需要,我可以為此發布一些入門代碼,我將在此處將其編輯為答案。

此外,您還談到了向量在另一個維度上增加的問題。 向量是一維的。 您可以將向量設為向量,但讓我們不要討論。

編輯附錄:

兆緩沖區的基本思想是,在緩沖區中分配所有必需的空間,然后初始化值,然后通過吸氣劑使用它。

數據布局為“標題,實體1,實體2,...,實體N”

// 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”和“ allocatednstances”。 因此,您確實有一個標頭,但它不是分配的緩沖區的一部分。 但是,您不想分配0字節,因此只需將usedInstances = 0設置為即可; locatedInstances = 0; buffer = nullptr;

我沒有編寫更改緩沖區大小的代碼,因為bitsquid ECS示例涵蓋了這一點,但是他沒有顯示首次初始化。 使用它們之前,請確保初始化n並分配它們,並為每個實體分配有意義的值。

您所執行的bitsquid ECS與發布的鏈接不同。 在這種情況下,他在並行數組中有幾個固定大小的不同對象。 存在一個實體,其質量,位置等。因此,entity [4]是質量等於“ mass [4]”且其加速度為“ acceleration [4]”的實體。 這使用指針算法來訪問數組元素。 (內置在數組中,不是std :: Array,不是std :: vector)

數據布局為“ Entity1,Entity2,...,EntityN,mass1,mass2,...,massN,position1,position2,...,positionN,velocity1 ...”,您就會明白。

如果您閱讀該文章,您會發現他對其他人所說的關於標准庫的說法基本相同。 您可以使用std容器存儲這些數組中的每個數組,或者可以分配一個兆緩沖區,並使用指針和“內置數組”數學方法來獲取每個條目在該緩沖區中的確切內存位置。 在經典的假裝舞步中,他甚至說:“這避免了Array類中可能存在的任何隱藏開銷,並且我們只有一個分配即可跟蹤。” 但是您不知道它是比std :: Array更快還是更慢,並且您引入了很多錯誤和額外的開發時間來處理原始指針。

我想我明白了您要做什么。

有很多問題。 第一。 您正在建立一個隨機數據的緩沖區,告訴C ++它的Vector大小是Vector。 但是,您實際上從來沒有真正將構造函數調用為Vector,它將初始化指針並將其內部構造為可行的值。

這已在此處得到解答: 在已分配的內存上調用構造函數

第二個問題是線

instanceData.vertices[i] = vertices;

instanceData.vertices是指向Vector的指針,因此您實際上需要編寫

(*(instanceData.vertices))[i]  

第三個問題是*(instanceData.vertices)的內容是浮點數,而不是Vector,因此您不能在那里進行賦值。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM