2009-08-05 130 views
1

自從我寫了C/C++之後的幾年,現在我面臨着一個我自己無法解決的問題。被覆蓋的C++變量數據

考慮以下結構:

struct InputData 
{ 
    float diameter; 
    float length; 
    int vertIndex; 
    struct InputData *parent; 
    vector<InputData*> children; 
    bool deadEnd; 

    InputData(float dia, float lngth) 
    { 
     diameter = dia; 
     length = lngth; 
     vertIndex = NULL; 
     parent = NULL; 
     deadEnd = false; 
    } 
}; 

我開始時通過定義節點的數量,以及它們的父/子關係:

InputData i0 = InputData(3.0f, 3.0f); 
InputData i1 = InputData(2.0f, 2.0f); 
InputData i2 = InputData(1.0f, 1.0f); 
InputData i3 = InputData(1.0f, 1.0f); 
InputData i4 = InputData(1.0f, 1.0f); 
InputData i5 = InputData(1.01f, 0.5f); 

i0.children.push_back(&i1); 
i1.children.push_back(&i2); 
i2.children.push_back(&i3); 
i3.children.push_back(&i4); 
i4.children.push_back(&i5); 

i1.parent = &i0; 
i2.parent = &i1; 
i3.parent = &i2; 
i4.parent = &i3; 
i5.parent = &i4; 

需要注意的是酷睿i5作爲唯一的節點不有任何孩子。

我然後繼續用這個數據做了一些工作(調用BuildMeshVertices(從& I0,&頂點)的main()),並最終將孩子I5:

void BuildMeshVertices(InputData* current, vector<SimpleVertex> *vertices) 
{ 
    //Do work 

    if(current->children.size() == 1) 
    { 
     BuildMeshVertices(current->children[0], vertices); 
    } 
    else if(current->children.size() == 0 && current->deadEnd == false) 
    { 
     InputData iDeadEnd = InputData(1.01f, 0.5f); 
     iDeadEnd.deadEnd = true; 
     iDeadEnd.parent = current; 
     current->children.push_back(&iDeadEnd);  

     BuildMeshVertices(&iDeadEnd, vertices); 
    } 
} 

之後一切很好。 i0有一個孩子(i1),i1有一個孩子(i2),等等,i5現在也有一個孩子。

我調用另一個函數(BuildMeshIndices()),並突然在這個函數(第63行)中添加了幾行代碼,新添加到i5的子數據被覆蓋。 i5仍然指向正確的孩子,但這個孩子的數據突然出現亂碼。

下面是截圖before and after(抱歉的聯繫,但我不允許使用IMG標記)

我想不通爲什麼會這樣,但我有它得到的東西做的感覺我的內存管理不善?

UPDATE另外它不必這樣做。例如,如果將子向量更改爲值的向量是首選的C++方式,那麼我更喜歡這一點。我試圖評論答案,但我不確定你們是否看到了評論(根據常見問題,你需要50條評論才能發表評論)?

下面是完整的源代碼(一切不必要剝離出來,但足以重現錯誤):

#include "stdafx.h" 
#include <vector> 

using std::vector; 

struct InputData 
{ 
    float diameter; 
    float length; 
    int vertIndex; 
    struct InputData *parent; 
    vector<InputData*> children; 
    bool deadEnd; 

    InputData(float dia, float lngth) 
    { 
     diameter = dia; 
     length = lngth; 
     vertIndex = NULL; 
     parent = NULL; 
     deadEnd = false; 
    } 
}; 

//-------------------------------------------------------------------------------------- 
// Vertex types 
//-------------------------------------------------------------------------------------- 
struct SimpleVertex 
{ 
    float Pos; 

    SimpleVertex(float Position) 
    { 
     Pos = Position; 
    } 
}; 

void BuildMeshVertices(InputData* current, vector<SimpleVertex> *vertices) 
{ 
    current->vertIndex = vertices->size(); 

    //Add vertices.. 

    if(current->children.size() == 1) 
    { 
     BuildMeshVertices(current->children[0], vertices); 
    } 
    else if(current->children.size() == 0 && current->deadEnd == false) 
    { 
     InputData iDeadEnd = InputData(1.01f, 0.5f); 
     iDeadEnd.deadEnd = true; 
     iDeadEnd.parent = current; 
     current->children.push_back(&iDeadEnd);  

     BuildMeshVertices(&iDeadEnd, vertices); 
    } 
} 

void BuildMeshIndices(InputData* current, vector<unsigned long> *indices) 
{ 
    indices->push_back(current->vertIndex+2); 
    indices->push_back(current->vertIndex+0); 
    indices->push_back(current->vertIndex+1); 
    indices->push_back(current->vertIndex+3); 
    indices->push_back(current->vertIndex+0); 
    indices->push_back(current->vertIndex+2); 

    InputData *parent = current->parent; 

    unsigned long vOffset; 

    if(parent != NULL && parent->children.size() == 1) 
    { 
     vOffset = (unsigned long)current->vertIndex; 

     indices->push_back(vOffset+7); 
     indices->push_back(vOffset+5); 
     indices->push_back(vOffset+4); 
     indices->push_back(vOffset+6); 
     indices->push_back(vOffset+5); 
     indices->push_back(vOffset+7); 

     indices->push_back(vOffset+10); 
     indices->push_back(vOffset+8); 
     indices->push_back(vOffset+9); 
     indices->push_back(vOffset+11); 
     indices->push_back(vOffset+8); 
     indices->push_back(vOffset+10); 

     indices->push_back(vOffset+15); 
     indices->push_back(vOffset+13); 
     indices->push_back(vOffset+12); 
     indices->push_back(vOffset+14); 
     indices->push_back(vOffset+13); 
     indices->push_back(vOffset+15); 

     indices->push_back(vOffset+18); 
     indices->push_back(vOffset+16); 
     indices->push_back(vOffset+17); 
     indices->push_back(vOffset+19); 
     indices->push_back(vOffset+16); 
     indices->push_back(vOffset+18); 
    } 

    if(current->children.size() == 1 && current->deadEnd == false) 
    { 
     BuildMeshIndices(current->children[0], indices); 
    } 
} 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    InputData i0 = InputData(3.0f, 3.0f); 
    InputData i1 = InputData(2.0f, 2.0f); 
    InputData i2 = InputData(1.0f, 1.0f); 
    InputData i3 = InputData(1.0f, 1.0f); 
    InputData i4 = InputData(1.0f, 1.0f); 
    InputData i5 = InputData(1.01f, 0.5f); 

    i0.children.push_back(&i1); 
    i1.children.push_back(&i2); 
    i2.children.push_back(&i3); 
    i3.children.push_back(&i4); 
    i4.children.push_back(&i5); 

    i1.parent = &i0; 
    i2.parent = &i1; 
    i3.parent = &i2; 
    i4.parent = &i3; 
    i5.parent = &i4; 

    // Create vertex buffer 
    vector<SimpleVertex> vertices; 

    BuildMeshVertices(&i0, &vertices); 

    // Create index buffer 
    vector<unsigned long> indices; 

    BuildMeshIndices(&i0, &indices); 

    return 0; 
} 

回答

1

將原始指針更改爲smart pointers,您將遇到內存管理問題。

你不需要複製所有的提升到你的項目,只需要標題。

#include <vector> 
#include <boost/shared_ptr.hpp> 
#include <boost/weak_ptr.hpp> 

struct InputData 
{ 
    float diameter; 
    float length; 
    unsigned long vertIndex; 
    boost::weak_ptr<InputData> parent; 
    std::vector< boost::shared_ptr<InputData> > children; 
    bool deadEnd; 

    InputData(float dia, float lngth, boost::weak_ptr<InputData> p = boost::weak_ptr<InputData>(), bool de = false) 
     : diameter(dia), length(lngth), vertIndex(0), parent(p), deadEnd(de) {} 
}; 

struct SimpleVertex 
{ 
    float Pos; 

    SimpleVertex(float position) : Pos(position) {} 
}; 

void BuildMeshVertices(boost::shared_ptr<InputData> current, std::vector<SimpleVertex>& vertices) 
{ 
    current->vertIndex = vertices.size(); 

    //Add vertices.. 
    if(current->children.size() == 1) 
    { 
     BuildMeshVertices(current->children[0], vertices); 
    } 
    else if(current->children.size() == 0 && current->deadEnd == false) 
    { 
      // this was a stack variable, so the pointer became invalid when going out of ambit. 
     boost::shared_ptr<InputData> iDeadEnd(new InputData(1.01f, 0.5f, current, true)); 
     current->children.push_back(iDeadEnd);   

     BuildMeshVertices(iDeadEnd, vertices); 
    } 
} 

void BuildMeshIndices(boost::shared_ptr<InputData> current, std::vector<unsigned long>& indices) 
{ 
    unsigned long vi = current->vertIndex; 
    unsigned long ioffset[] = { vi+2, vi, vi+1, vi+3, vi, vi+2}; 
    indices.insert(indices.end(), ioffset, ioffset+6); 

    boost::shared_ptr<InputData> parent = current->parent.lock(); 
    if (parent && parent->children.size() == 1) 
    { 
     unsigned long offs = current->vertIndex; 
      unsigned long voffset[] = 
      { offs+7, offs+5, offs+4, offs+6, offs+5, offs+7, 
      offs+10, offs+8, offs+9, offs+11, offs+8, offs+10, 
      offs+15, offs+13, offs+12, offs+14, offs+13, offs+15, 
      offs+18, offs+16, offs+17, offs+19, offs+16, offs+18 }; 
      indices.insert(indices.end(), voffset, voffset+24); 
    } 

    if(current->children.size() == 1 && current->deadEnd == false) 
    { 
     BuildMeshIndices(current->children[0], indices); 
    } 
} 

int main() 
{ 
    boost::shared_ptr<InputData> i0(new InputData(3.0f, 3.0f)); 
    boost::shared_ptr<InputData> i1(new InputData(2.0f, 2.0f)); 
    boost::shared_ptr<InputData> i2(new InputData(1.0f, 1.0f)); 
    boost::shared_ptr<InputData> i3(new InputData(1.0f, 1.0f)); 
    boost::shared_ptr<InputData> i4(new InputData(1.0f, 1.0f)); 
    boost::shared_ptr<InputData> i5(new InputData(1.01f, 0.5f)); 

    i0->children.push_back(i1); 
    i1->children.push_back(i2); 
    i2->children.push_back(i3); 
    i3->children.push_back(i4); 
    i4->children.push_back(i5); 

    i1->parent = i0; 
    i2->parent = i1; 
    i3->parent = i2; 
    i4->parent = i3; 
    i5->parent = i4; 

    // Create vertex buffer 
    std::vector<SimpleVertex> vertices; 
    BuildMeshVertices(i0, vertices); 

    // Create index buffer 
    std::vector<unsigned long> indices; 
    BuildMeshIndices(i0, indices); 

    return 0; 
} 

認爲你仍然有一半C,一半C++的髒代碼...你應該選擇一種語言。

+0

令人驚歎!我不知道增強庫,但看起來我必須瞭解它。 – Tchami 2009-08-06 10:42:14

+0

共享/弱指針被添加到C++ 03標準。一些編譯器在tr1 /內存頭中的std :: tr1命名空間中實現了它,或者在編譯器中實現了在內存頭中的std命名空間中支持C++ 0x的編譯器。 – 2009-08-18 13:30:49

7

你推指針到堆棧對象到您的載體。一旦執行離開作用域,堆棧對象將被破壞,並且內存將被重用,從而導致僞造值。嘗試

InputData *iDeadEnd = new InputData(1.01f, 0.5f); 
iDeadEnd->deadEnd = true; 
iDeadEnd->parent = current; 
current->children.push_back(iDeadEnd); 

然後,您將不得不在適當的時間釋放該內存。

+0

非常感謝(和其他建議類似的人)!這似乎是訣竅,但是什麼是釋放內存的首選方式?什麼時候? – Tchami 2009-08-05 14:27:19

+0

你可以使用boost :: shared_ptr或boost :: ptr_vector – bdonlan 2009-08-05 16:12:49

+0

你必須走樹並手動釋放內存。這不是特別困難*,但錯過了一步,你會有內存泄漏。 – 2009-08-05 16:15:04

1

您應該使用動態內存來處理指針。 當您退出功能BuildMeshVertices時,InputData將被銷燬,因此數據將被垃圾回收,否則您將收到內存異常。

你應該這樣做

InputData * iDeadEnd = new InputData(1.01f, 0.5f); 

,而不是

InputData iDeadEnd = InputData(1.01f, 0.5f); 
0

那麼你BuildMeshVertices函數退出iDeadEnd(I5的孩子)的解構,因爲你宣佈它在堆棧上的時刻,通過退出函數使整個堆棧框架失效並解構所有對象。您要麼動態分配iDeadEnd,要麼從根本上重新考慮如何定義樹。你會更好讓每個結構保持InputData(不InputData *)的載體中,然後將它們設置如下:

InputData i0 = InputData(3.0f, 3.0f); 
i0.children.push_back(InputData(2.0f, 2.0f)); 
i0.children[0].children.push_back(InputData(1.0f, 1.0f)); 

即使是很不理想的原因很明顯。定義元素樹永遠不是最有趣的事情。

1

你在STACK上實例化了iDeadEnd,並把一個指向堆棧地址的指針!當函數終止並且堆棧展開時,iDeadEnd的數據將會變成垃圾。

InputData *iDeadEnd = new InputData(1.01f, 0.5f); 
iDeadEnd->deadEnd = true; 
iDeadEnd->parent = current; 
current->children.push_back(iDeadEnd);   

BuildMeshVertices(iDeadEnd, vertices); 

你現在的問題是,需要當你用它做被明確釋放對iDeadEnd內存。