提问人:Joao Pincho 提问时间:8/23/2022 更新时间:8/23/2022 访问量:65
将值推送到 std::vector 中,但似乎在错误的地址
pushed value into std::vector but seems to be at wrong address
问:
我有这段代码,从 Assimp aiNode 树转换为我自己的树数据结构。这是一个非常简单的递归函数,它遍历树,用节点数据填充结构,并为每个子节点调用自身。唯一的区别是,我不是动态分配每个节点,而是将其推送到向量中,并使用索引而不是指针来连接它们。
int AddNode( ModelDescriptor &LoadedModelDescriptor, const int ParentIndex, const aiNode *CurrentAssimpNode )
{
int NewIndex = (int) LoadedModelDescriptor.NodeTree.size();
LoadedModelDescriptor.NodeTree.push_back( MeshTreeNode() );
LoadedModelDescriptor.NodeTree[NewIndex].Name.assign( CurrentAssimpNode->mName.C_Str() );
LoadedModelDescriptor.NodeTree[NewIndex].ParentNode = ParentIndex;
LoadedModelDescriptor.NodeTree[NewIndex].DefaultTransformationMatrix = glm::transpose( glm::make_mat4( (float *) &CurrentAssimpNode->mTransformation ) );
LOG_DEBUG("processing node %u %s %u meshes %u children", NewIndex, LoadedModelDescriptor.NodeTree[NewIndex].Name.c_str(), CurrentAssimpNode->mNumMeshes, CurrentAssimpNode->mNumChildren );
for ( unsigned MeshIterator = 0; MeshIterator < CurrentAssimpNode->mNumMeshes; ++MeshIterator )
{
LoadedModelDescriptor.NodeTree[NewIndex].MeshIndices.push_back( CurrentAssimpNode->mMeshes[MeshIterator] );
}
for ( unsigned ChildIterator = 0; ChildIterator < CurrentAssimpNode->mNumChildren; ++ChildIterator )
{
LoadedModelDescriptor.NodeTree[NewIndex].ChildNodes.push_back( AddNode( LoadedModelDescriptor, NewIndex, CurrentAssimpNode->mChildren[ChildIterator] ) );
}
LOG_DEBUG("finished processing node %u %s %u meshes %u children", NewIndex, LoadedModelDescriptor.NodeTree[NewIndex].Name.c_str(), LoadedModelDescriptor.NodeTree[NewIndex].MeshIndices.size(), LoadedModelDescriptor.NodeTree[NewIndex].ChildNodes.size());
return NewIndex;
}
以下是使用的相关结构:
struct MeshTreeNode
{
std::string Name;
glm::mat4 DefaultTransformationMatrix;
std::vector <uint32_t> MeshIndices;
std::vector <int> ChildNodes;
int ParentNode;
};
struct ModelDescriptor
{
std::string Name;
std::vector <MeshTreeNode> NodeTree;
std::vector <MeshDescriptor> Meshes;
std::vector <LightDescriptor> Lights;
BoundingBox BBox;
};
没什么,没有隐藏的东西。在 Windows 下可以完美运行,但昨晚在 Debian 上使用 GCC 运行它时遇到了一个令人讨厌的惊喜。调用后,NodeTree 已完全填充,但所有节点都没有填充的 ChildNodes 向量。 所以基本上,第一个节点被认为是没有子节点的,节点树就在那里结束了。 经过相当多的调试,我注意到一切都运行顺利,正在添加子节点,但由于某种原因,最终树的内容不同。我认为递归调用的行为不符合预期,就当时在内存中加载的内容而言。 于是我把这个小小的push_back电话分成了两行:
int ChildNodeIndex = AddNode( LoadedModelDescriptor, NewIndex, CurrentAssimpNode->mChildren[ChildIterator] );
LoadedModelDescriptor.NodeTree[NewIndex].ChildNodes.push_back( ChildNodeIndex );
基本上只是在推送索引之前暂时将索引存储在变量中,但现在它可以工作了。显然,该索引被推送到某个向量中,而该向量在push_back实际运行时不再有效。但根据我的理解,它绝对应该是,它应该是调用堆栈中的最后一件事,无论向量因为递归调用而在内部重新分配了多少次,它在堆栈展开期间仍然应该是准确的,因为我认为它只会将 std::vector 的“this”推送到堆栈上。
谁能告诉我为什么会这样?感觉不对劲。
答: 暂无答案
评论
int NewIndex = (int) LoadedModelDescriptor.NodeTree.size();
-- 也许是题外话,但如果你只是在 之后有 ,然后简单地在整个函数的其余部分使用,那就没有必要了。NewIndex
auto& lastItem = LoadedModelDescriptor.NodeTree.back();
push_back()
lastItem