如何让循环内动态分配的struct数组在函数外持久可用?
问题:动态分配的ShapeEntity数组无法在函数外保留
我自学C/C++,开发读取游戏文件格式的程序时,已经成功获取所需数据,但这些数据只能在读取循环内访问,没法在函数其他位置或者函数外使用。我知道普通变量循环结束会销毁,但我用了new动态分配了ShapeEntity结构体数组。因为元素数量要读取文件后才能确定,没法提前初始化。我需要这些数据供后续使用,只在循环内存在完全没用。
以下是我的代码:
typedef struct { uint32_t FbxHash; string ShapeName; float ShapeTransforms[18]; bool converted; } ShapeEntity;
读取文件的函数:
void CompositeMeshReader(FILE* MeshCompPtr) { uint8_t NumberOfLods; uint8_t NumberOfMeshes; uint8_t ShadersPerMesh; float GlobalTransforms[6]; int NumberOfShapes; int CurrentLOD; int w; int y; int i; int j; int k; string fname; string* fnameptr = &fname; uint8_t z; uint8_t NullProperty; uint8_t UnknownByte; bool stay = true; fseek(MeshCompPtr, 5, SEEK_SET); StringSkipper(fnameptr); cout << "Lods Settings File: " << fname << endl; fread(&NumberOfLods, 1, 1, MeshCompPtr); fseek(MeshCompPtr, 3, SEEK_CUR); cout << "Lods detected: " << int(NumberOfLods) << ", which one to extract?" << endl; cout << "for lod 0, type 0, lod 1, type 1, etc" << endl; cin >> i; fname = ""; CurrentLOD = 0; while ((CurrentLOD < NumberOfLods) && (stay == true)) { fread(&NullProperty, 1, 1, MeshCompPtr); fread(&ShadersPerMesh, 1, 1, MeshCompPtr); fread(&NumberOfMeshes, 1, 1, MeshCompPtr); for (j = 0; j < NumberOfMeshes; j++) { StringSkipper(fnameptr); if (i == CurrentLOD) { cout << "Mesh " << j << " " << fname << endl << endl; } for (k = 0; k < ShadersPerMesh; k++) { StringSkipper(fnameptr); if (i == CurrentLOD) { cout << "Shader " << k << " " << fname << endl << endl; } } } fread(GlobalTransforms, sizeof GlobalTransforms[0], 6, MeshCompPtr); fseek(MeshCompPtr, 8, SEEK_CUR); fread(&UnknownByte, 1, 1, MeshCompPtr); fread(&NumberOfShapes, 4, 1, MeshCompPtr); ShapeEntity* Shapes = new ShapeEntity[NumberOfShapes]; // 这是我需要保留的数组 for (w = 0; w < NumberOfShapes; w++) { fread(&Shapes[w].FbxHash, 4, 1, MeshCompPtr); StringSkipper(fnameptr); Shapes[w].ShapeName = fname; fread(Shapes[w].ShapeTransforms, 4, 18, MeshCompPtr); Shapes[w].converted = false; } fseek(MeshCompPtr, ShadersPerMesh * 24, SEEK_CUR); if (i != CurrentLOD) { cout << "Shapes destroyed" << endl; delete[] Shapes; } else { print(Shapes, ShadersPerMesh, NumberOfMeshes, NumberOfShapes, GlobalTransforms); stay = false; } CurrentLOD++; } return; }
我尝试让Shapes数组在函数返回后仍能使用,但离开while循环后它就无法访问了,难道不重写整个程序就无法解决吗?我多方查找仍未找到合适的解决方案。
核心原因
你用new分配的堆内存本身不会在循环结束后销毁,但指向该内存的局部指针Shapes会在循环迭代结束(或函数返回)时被销毁。如果没有保存这个指针的副本,后续就无法再访问堆上的那片内存,导致数据“丢失”。
解决方案
方案1:返回封装后的结果结构体
把函数返回类型从void改为自定义结构体,同时包含数组指针、元素数量以及其他需要保留的数据(比如GlobalTransforms等):
// 封装返回结果的结构体 struct ShapeReadResult { ShapeEntity* shapes; int shapeCount; float globalTransforms[6]; int shadersPerMesh; int numberOfMeshes; }; ShapeReadResult CompositeMeshReader(FILE* MeshCompPtr) { ShapeReadResult result = {nullptr, 0}; // ... 原有代码逻辑 ... while ((CurrentLOD < NumberOfLods) && (stay == true)) { // ... 原有代码逻辑 ... if (i != CurrentLOD) { delete[] Shapes; } else { // 将数据赋值给结果结构体 result.shapes = Shapes; result.shapeCount = NumberOfShapes; memcpy(result.globalTransforms, GlobalTransforms, sizeof(GlobalTransforms)); result.shadersPerMesh = ShadersPerMesh; result.numberOfMeshes = NumberOfMeshes; stay = false; } CurrentLOD++; } return result; }
使用注意:用完数据后必须手动调用delete[] result.shapes,否则会造成内存泄漏。
方案2:使用输出参数传递指针
在函数参数中添加指针类型的输出参数,用来接收数组指针和元素数量:
void CompositeMeshReader(FILE* MeshCompPtr, ShapeEntity** outShapes, int* outShapeCount, float outGlobalTransforms[6], int* outShadersPerMesh, int* outNumberOfMeshes) { // 初始化输出参数 *outShapes = nullptr; *outShapeCount = 0; // ... 原有代码逻辑 ... while ((CurrentLOD < NumberOfLods) && (stay == true)) { // ... 原有代码逻辑 ... if (i != CurrentLOD) { delete[] Shapes; } else { *outShapes = Shapes; *outShapeCount = NumberOfShapes; memcpy(outGlobalTransforms, GlobalTransforms, sizeof(GlobalTransforms)); *outShadersPerMesh = ShadersPerMesh; *outNumberOfMeshes = NumberOfMeshes; stay = false; } CurrentLOD++; } }
调用示例:
ShapeEntity* myShapes = nullptr; int shapeCount = 0; float transforms[6]; int shadersPerMesh, meshCount; CompositeMeshReader(filePtr, &myShapes, &shapeCount, transforms, &shadersPerMesh, &meshCount); // 使用数据 // ... // 用完释放内存 delete[] myShapes;
方案3:用std::vector替代手动动态分配(推荐)
C++中优先使用标准容器std::vector,它会自动管理内存,无需手动调用new/delete,还能轻松在函数间传递:
#include <vector> // 封装返回结果的结构体 struct ShapeReadResult { std::vector<ShapeEntity> shapes; float globalTransforms[6]; int shadersPerMesh; int numberOfMeshes; }; ShapeReadResult CompositeMeshReader(FILE* MeshCompPtr) { ShapeReadResult result; // ... 原有代码逻辑 ... while ((CurrentLOD < NumberOfLods) && (stay == true)) { // ... 原有代码逻辑 ... fread(&NumberOfShapes, 4, 1, MeshCompPtr); // 用vector替代new分配数组 std::vector<ShapeEntity> Shapes(NumberOfShapes); for (w = 0; w < NumberOfShapes; w++) { fread(&Shapes[w].FbxHash, 4, 1, MeshCompPtr); StringSkipper(fnameptr); Shapes[w].ShapeName = fname; fread(&Shapes[w].ShapeTransforms, 4, 18, MeshCompPtr); Shapes[w].converted = false; } // ... 原有代码逻辑 ... if (i != CurrentLOD) { // vector超出作用域会自动释放内存,无需手动操作 } else { // 用std::move转移vector所有权,避免拷贝开销 result.shapes = std::move(Shapes); memcpy(result.globalTransforms, GlobalTransforms, sizeof(GlobalTransforms)); result.shadersPerMesh = ShadersPerMesh; result.numberOfMeshes = NumberOfMeshes; stay = false; } CurrentLOD++; } return result; }
这种方法无需手动管理内存,彻底避免内存泄漏风险,是最推荐的C++风格解决方案。
内容的提问来源于stack exchange,提问作者V12Style
相关产品推荐
相关产品推荐

