2009-08-05 91 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内存。