由new引起的C++bad_alloc

C++ bad_alloc caused by new?

本文关键字:C++bad alloc new      更新时间:2023-10-16

[前注:我已经阅读了StackOverflow中现有的线程。似乎没有任何问题]

我正在研究Quake 2 MD2格式。在新建指针数组后,我似乎得到了一个错误的分配。然而,如果我做了一些可怕的指针操作,一切都很好。我想问题是,为什么我会遇到这样的例外?

第一个"MD2Model::Load"有效。我在它获得异常后发布的那个。

基本结构:

struct MD2Header
{
    int nIdentifier;
    int nVersion;
    int nSkinWidth;
    int nSkinHeight;
    int nFrameSize;
    int nNumSkins;
    int nNumVertices;
    int nNumUV;
    int nNumTriangles;
    int nNumCmds;
    int nNumFrames;
    int nOffsetSkins;
    int nOffsetUV;
    int nOffSetTriangles;
    int nOffsetFrames;
    int nOffsetCmds;
    int nOffsetEnd;
};
struct MD2Skin
{
    char szName[64];
};
struct MD2TexCoord
{
    short t;
    short u;
};
struct MD2Triangle
{
    short nVertex[3];
    short tu[3];
};
struct MD2Vertex
{
    float   fVertex[3];
    float   fNormal[3];
};
struct MD2Frame
{
    char szName[16];
    MD2Vertex* pVerts;
};

现在,读取.md2文件的函数:

bool MD2Model::Load( const char* pszName )
{
    FILE* pFile = NULL;
    fopen_s( &pFile, pszName, "rb" );
    if( !pFile )
        return false;
    /* Read Header */
    fread( &m_Header, sizeof(MD2Header), 1, pFile );
    /* Allocate Pointers */
    m_pSkins = new MD2Skin[m_Header.nNumSkins];
    m_pTexCoords = new MD2TexCoord[m_Header.nNumUV];
    m_pTriangles = new MD2Triangle[m_Header.nNumTriangles];
    m_pFrames = new MD2Frame[m_Header.nNumFrames];
    /* Read Skins */
    fseek( pFile, m_Header.nOffsetSkins, SEEK_SET );
    fread( m_pSkins, sizeof(MD2Skin), m_Header.nNumSkins, pFile );
    /* Read Texture Coords */
    fseek( pFile, m_Header.nOffsetUV, SEEK_SET );
    fread( m_pTexCoords, sizeof(MD2TexCoord), m_Header.nNumUV, pFile );
    /* Read Faces */
    fseek( pFile, m_Header.nOffSetTriangles, SEEK_SET );
    fread( m_pTriangles, sizeof(MD2Triangle), m_Header.nNumTriangles, pFile );
    /* Read Animations */
    struct stMD2Vertex
    {
        unsigned char nVertex[3];
        unsigned char nLightNormalIndex;
    };
    struct stMD2Frame
    {
        float fScale[3];
        float fTranslate[3];
        char szName[16];
        stMD2Vertex verts[1];
    };
    unsigned char pBuffer[30000];
    stMD2Frame* pTmp = (stMD2Frame*) pBuffer;
    fseek( pFile, m_Header.nOffsetFrames, SEEK_SET );
    for( int i = 0; i < m_Header.nNumFrames; i++ )
    {
        fread( pTmp, 1, m_Header.nFrameSize, pFile );
        m_pFrames[i].pVerts = new MD2Vertex[m_Header.nNumVertices];
        strcpy_s( m_pFrames[i].szName, pTmp->szName );
        for( int j = 0; j < m_Header.nNumVertices; j++ )
        {
            m_pFrames[i].pVerts[j].fVertex[0] = pTmp->verts[j].nVertex[0] *
                pTmp->fScale[0] + pTmp->fTranslate[0];
            m_pFrames[i].pVerts[j].fVertex[2] = -1 * (pTmp->verts[j].nVertex[1] *
                pTmp->fScale[1] + pTmp->fTranslate[1]);
            m_pFrames[i].pVerts[j].fVertex[1] = pTmp->verts[j].nVertex[2] *
                pTmp->fScale[2] + pTmp->fTranslate[2];
        }
    }
    return true;
}

调试期间转储的变量:

nNumSkins        1          int
nNumVertices     583        int
nNumUV           582        int
nNumTriangles    422        int
nNumFrames       1          int

(我最终移除了我的D3DXVECTOR3结构,所以它有点模糊。)

好吧。所以,在"for"循环中,就是它爆炸的地方。如果我这样做:

//  unsigned char pBuffer[30000];
//  stMD2Frame* pTmp = (stMD2Frame*) pBuffer;
    fseek( pFile, m_Header.nOffsetFrames, SEEK_SET );
    for( int i = 0; i < m_Header.nNumFrames; i++ )
    {
        stMD2Frame* pTmp = new stMD2Frame();
        fread( pTmp, 1, m_Header.nFrameSize, pFile );
        m_pFrames[i].pVerts = new MD2Vertex[m_Header.nNumVertices];
        strcpy_s( m_pFrames[0].szName, pTmp->szName );

在分配"m_pFrames[I].pVerts"语句期间,我得到了bad_alloc异常。有时,我没有得到它,但当我尝试新建D3D类时,我确实得到了例外(我假设无论以后我新建什么,我都会得到它)。我的MEM使用率非常低,所以可能是堆损坏吗?

事实上,我最终不得不在动画期间创建我的VertexBuffer。

我最终应该使用矢量吗?我知道他们的分配超出了需要,但这似乎是(最明显的)[最好的]方式。

我会检查行:

strcpy_s( m_pFrames[0].szName, pTmp->szName );

如果从文件加载的字符串不是以null终止的,则此副本最终可能会覆盖堆栈空间并导致损坏。

编辑

再看一遍,我认为问题在于您将stMD2Frame定义为

struct stMD2Frame
{
    float fScale[3];
    float fTranslate[3];
    char szName[16];
    stMD2Vertex verts[1];
};

但是这只具有用于一个顶点的空间。

当你在帧中读取时

fread( pTmp, 1, m_Header.nFrameSize, pFile );

你会破坏你的记忆。

我建议检查

sizeof(stMD2Frame)>=m_Header.nFrameSize 

在读取数据之前。