You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让循环内动态分配的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 23:44:54