vision

导航

小心陷阱:二维动态内存的不连续性

void new_test()
{
    int** pp;
    pp = new int*[10];
    for(int i=0; i<10; ++i)
    {
        pp[i] = new int[10];
    }
    //pp[0], pp[1], ... , pp[9]在内存中连续;
    //a1 = pp[0][0], pp[0][1], ... , pp[0][9]在内存中也是连续的;
    //a2 = pp[1][0], pp[1][1], ... , pp[1][9]在内存中也是连续的;
    //...
    //a9 = pp[9][0], pp[9][1], ... , pp[9][9]在内存中也是连续的;
    //然而 pp[0][9]与pp[1][0]是不连续的,pp[1][9]与pp[2][0]也不连续;
    //即用new申请的动态堆内存,一维连续二维不连续;
    //若从内存地址&(pp[0][0])连续写入10*10个int型数据则内存将会被破坏,然而这种破坏;
    //是合法的,编译器不会出警告或错误,但程序运行中会出现非常诡异的现象;
    //如某个变量突然莫名其妙的被改掉了,然而程序中并没有在任何地方改了它;
}

 以上为简化代码,下面为程序中实际遇到的情况:

void CXAnimation::_loadAnimFromFile(cchar* pfile)
{
    std::ifstream ifs(pfile, std::ios::binary);

    if(!ifs || !ifs.is_open())return;

    int num[2], i, iSet = 0, ii = sizeof(int);


    while(!ifs.eof())
    {
        ifs.read((char*)num, ii*2); //num[0] 帧数, num[1] 骨骼数;
        CXAnimSet animSet;
        m_animSets.push_back(animSet);
        CXAnimSet& rset = m_animSets[iSet];

        rset.nFrame = num[0];
        rset.pAnims = new float4x4*[num[0]];
        m_nBones = num[1];//骨骼数总是不变的;
        m_nb1 = num[1];
        int nbt = num[1]*16*ii;
        for(i=0; i<num[0]; ++i)
        {
            rset.pAnims[i] = new float4x4[num[1]];
            xeAssert(rset.pAnims[i] != NULL);
            ifs.read((char*)&(rset.pAnims[i][0]), nbt);
        }

        //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
        //特别注意: 下面这行代码是错误的,因为二维动态内存是不连续的;
        //所以下面的代码将导致内存不可预见的更改,比如m_nBones被莫名其妙的改掉了;
        //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 
        //ifs.read((char*)&(rset.pAnims[0][0]), num[0]*num[1]*16*ii);

        iSet++;

        ifs.peek();
    }
    
    //计算骨骼初始变换的逆,方便蒙皮计算时使用,不必每一帧都做重复的运算;
    _calcInitInversTM();


}

 

posted on 2013-05-07 23:04  释小天  阅读(203)  评论(0编辑  收藏  举报