小心陷阱:二维动态内存的不连续性
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(); }