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 作为唯一的节点没有任何子节点。
然后我继续使用这些数据做一些工作(从 main() 调用 BuildMeshVertices(&i0, &vertices)),并最终向 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仍然指向右边的孩子,但是这个孩子的数据突然乱码了。
这是之前和之后的屏幕截图(很抱歉该链接,但我不被允许使用IMG 标签)
我不明白为什么会发生这种情况,但我有一种感觉,这与我糟糕的内存管理有关?
更新 另外,也不必这样做。 例如,如果将子向量更改为值向量是首选的 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;
}
Been a few years since I've written C/C++, and now I'm facing a problem I just cannot seem to solve on my own.
Given the following struct:
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;
}
};
I start out by defining a number of nodes, and their parent/child relationship:
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;
Note that i5 as the only node doesn't have any children.
I then move on to do some work using this data (calling BuildMeshVertices(&i0, &vertices) from main()), and end up adding a child to 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);
}
}
After which everything is fine. i0 has one child (i1), i1 has a one child (i2), so on and so forth and i5 now has a child as well.
I call another function (BuildMeshIndices()), and suddenly a few lines into this function (line 63) the data for the newly added child to i5 is being overwritten. i5 still points to the right child, but the data for this child is suddenly garbled.
Here's a screenshot before and after (sorry about the link, but I weren't allowed to use IMG tags)
I cannot figure out why this happens, but I've got a feeling it's got something to do with my poor memory management?
UPDATE Also it doesn't have to be done this way. If for example changing the children vector to a vector of values is the preferred C++ way, I would much prefer that. I've tried to comment on the answers, but I'm not sure you guys are seeing the comments (According to the FAQ you need 50 reputation to leave comments)?
Below is the full source code (with everything unnecessary stripped out, but enough to reproduce the error):
#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;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
您正在将指向堆栈对象的指针推入向量中。 一旦执行离开作用域,堆栈对象将被销毁,内存将被重用,从而产生虚假值。 尝试
然后您必须在适当的时间释放该内存。
You are pushing the pointer to a stack object into your vector. Once execution leaves scope that stack object will get destroyed and the memory will be reused, resulting in a bogus value. Try
Then you'll have to free that memory at the appropriate time.
将原始指针更改为 智能指针 你会得到内存管理问题。
您不需要将所有 boost 复制到项目中,只需复制所需的标头即可。
认为你仍然有一半 C、一半 C++ 脏代码......你应该选择一种语言。
Change raw pointers to smart pointers and you will get ride of memory management problems.
You don't need to copy all boost to your project, just required headers.
Think you still have a half C, half C++ dirty code... you should choose a language.
当您的 BuildMeshVertices 函数退出时,iDeadEnd(i5 的子级)就会被解构,因为您在堆栈上声明了它,并且通过退出该函数,整个堆栈帧将失效并且所有对象都会被解构。 您要么想要动态分配 iDeadEnd,要么从根本上重新思考如何定义树。 您最好让每个结构体保存一个InputData(而不是InputData*)向量,然后按如下方式设置它们:
等等
即使由于显而易见的原因,这也远非理想。 不过,定义元素树从来都不是最有趣的事情。
The moment your BuildMeshVertices function exits then iDeadEnd (i5's child) is deconstructed because you declared it on the stack and by exiting the function the entire stack frame is invalidated and all object deconstructed. You either want to dynamically allocate iDeadEnd or radically re-think how you define a tree. You'd be better off having each struct hold a vector of InputData (not InputData*) and then setting them up as follows:
etc
Even that is far from ideal for obvious reasons. Defining a tree of elements is never the most fun of things to do though.
您应该使用动态内存来处理指针。 当你退出BuildMeshVertices函数时,InputData将被销毁,因此数据将被垃圾化或者你将得到内存异常。
你应该做类似的事情
而不是
You should use dynamic memory to work with pointers. InputData will be destroyed when you go out of the function BuildMeshVertices, so the data will be garbaged or you will get a memory exception.
You should do something like
instead of
您正在堆栈上实例化 iDeadEnd,并获取指向堆栈地址的指针! 当函数终止并且堆栈展开时,iDeadEnd 的数据将出现乱码。
您现在遇到的问题是,当您使用完 iDeadEnd 的内存后,需要显式地释放它。
You are instancing iDeadEnd on the STACK, and taking a pointer to the stack address! When the functions terminate and the stack unwinds, the data for iDeadEnd is going to garble.
The problem you now have is that the memory for iDeadEnd needs to be explicitly deallocated when you're done with it.