用new分配4k int后的内存覆盖



在调试了一些非常奇怪的行为后,比如向量从0大小突然变成负值,我意识到这是在用new分配4000 int后发生的。我不明白,4k int(~15KB)并没有那么大,即使是,为什么它会干扰我的内存?视频:https://drive.google.com/file/d/0B_iN9pcbyoiKQV9lNllLWktfOGc/edit?usp=sharing

在视频中,你看到的结构是这样的:

struct TileMap{
int * pTileMap;
int mapW, mapH;
float hSpacing, vSpacing;
sprite::InstancedSprites m_tileInstSprites;
sprite::InstancesVertexBuffer m_IVB;
TileMap():pTileMap(nullptr){}
~TileMap(){ if(pTileMap) delete [] pTileMap; }
};
std::vector<TileMap> m_vTileMaps;

编辑

所以,即使注释掉了分配,几步后也会发生同样的事情,我想是前一刻的覆盖吗?有关于如何调试的提示吗?

编辑2

问题与指针无关,问题出在这里:

sprite::InstancedSprites::InstancedSprites()
:
m_drawCall(6),
m_drawCall_warpException(6)
{
m_drawable.AddPipelineState( &m_pipeState );
m_drawable.SetDrawCall( &m_drawCall );
m_drawable_warpException.AddPipelineState( &m_pipeState );
m_drawable_warpException.SetDrawCall( &m_drawCall_warpException );
}

这就是ctor,我认为它应该做得很好,drawable中的所有内容都是std::vector(AddPipelineState正在向向量添加)。

我"解决"它的方法是添加与ctor在这种方法中所做的相同的工作:

void sprite::InstancedSprites::Initialize( dx::BindPSShaderResourceView &                          pTextureBinder_p, dx::BindOMBlendState & pBlendBinder, dx::BindPSSampler & pSampleState,                      InstancesVertexBuffer & pIVB_p )
{
// DBG
m_drawable.Clear();
m_drawable.AddPipelineState( &m_pipeState );
m_drawable.SetDrawCall( &m_drawCall );
m_drawable_warpException.Clear();
m_drawable_warpException.AddPipelineState( &m_pipeState );
m_drawable_warpException.SetDrawCall( &m_drawCall_warpException );
m_pipeState.Reset();
m_pipeState.AddBinderCommand( &pTextureBinder_p );
m_pipeState.AddBinderCommand( &pBlendBinder );
m_pipeState.AddBinderCommand( &pSampleState );
m_pipeState.AddBinderCommand( pIVB_p.GetBinder() );
// missing, IA and camera binds
m_pIVBref = &pIVB_p;
}

上半部分是修复,我没有(我有方法),因为ctor已经做了。。。所以我真的不明白。如果内部dravable使用向量,那么这不可能是三的规则吗?

编辑3

最终的解决方案是,一个根本不复制的cpy ctor,问题是,这些dratables将其保存在所有者类上的数据上,因此在复制时,它们在获取带有数据的向量时不再有效…:

sprite::InstancedSprites::InstancedSprites( InstancedSprites & /*other_p*/ )
:
m_drawCall(6),
m_drawCall_warpException(6)
{   
m_drawable.AddPipelineState( &m_pipeState );
m_drawable.SetDrawCall( &m_drawCall );
m_drawable_warpException.AddPipelineState( &m_pipeState );
m_drawable_warpException.SetDrawCall( &m_drawCall_warpException );
}
std::vector<TileMap> m_vTileMaps;

您正在创建TileMap对象的矢量。TileMap违反了三规则,任何违反该规则的类型都不能在向量中安全使用。换句话说,这个简单的类测试显示了将要发生的问题:

int main()
{
TileMap x;
// assume x has allocated the ints
//..
TileMap y = x;  // trouble, trouble
TileMap z;
//.. assume z has allocated ints
z = x;   // more trouble
}  // double deletion error and memory leak on program exit

上面的代码不使用矢量,但显示了矢量内部将执行的操作类型。您可以看到在制作副本时出现的问题。

矢量类将创建TileMap的副本,并且TileMap对象不可安全复制。您需要添加一个用户定义的复制构造函数、赋值运算符和析构函数(您提供的),以使类正确复制。

另一种解决方案是存储指向TileMap的指针向量(最好是智能指针)。

std::vector<TileMap*> m_vTileMaps;
m_vTileMaps.reserve(4000);
m_vTileMaps.push_back(new TileMap());

然后在释放内存时:

for(auto it=m_vTileMaps.begin(); it!=m_vTileMaps.end(); ++it)
{
delete(*it);
}
m_vTileMaps.clear();

或者通过使用shared_ptr,您可以忘记最后一部分。

另一个解决方案是在TileMap中使用矢量。你已经在使用矢量了,但你拒绝在它真正重要的地方使用它:

struct TileMap
{
std::vector<int> pTileMap;
int mapW, mapH;
float hSpacing, vSpacing;
sprite::InstancedSprites m_tileInstSprites;
sprite::InstancesVertexBuffer m_IVB;
};
std::vector<TileMap> m_vTileMaps;  // this is ok now

TileMap类现在可以在向量中安全地使用(我假设sprite::*类型可以安全地复制)。您也不再需要在析构函数中执行delete[]操作。

最新更新