vector的erase()影响

今天在调试一个程序,发现返回的数值有问题。

程序结构如下所述:

为了防止对内存的反复分配和销毁带来的效率问题,在程序中自己写了个内存管理程序,其目的是调用它的接口分配内存,调用它的接口销毁内存。实际上所谓的销毁并不是真正地销毁,而是把内存放到了一个没有使用的列表中。这个里面有两个列表:

使用的内存列表,采用map管理,key为内存的地址,值为自定义的一个结构:

struct Smm
{
   char *buf;
   int len;
};
map<int, Smm> mapUsed;

空闲的内存列表,采用vector管理:

vector<Smm> vecFree;


由于使用中的问题发生在分配内存的函数中,所以本文只说明关于分配接口的逻辑流程。

分配内存的接口非常简单:

char *CreateMm(int len);

内部的实现逻辑如下:

char *CreateMm(int len)
{
  Smm *pmm = NULL;
  int index = 0;
  if ( (index = search_in_free(len)) >= 0 )
  {
      pmm = &vecFree[index];
      mapUsed[pmm->buf] = *pmm;            // 重新加入到正在使用的列表中
      vecFree.erase(vecFree.begin()+index);// 从空闲列表中删除
      return pmm->buf;
  }

// 空闲列表中没有足够的内存,所以重新创建
  Smm mm;
  mm.buf = new char[len];
  mm.len = len;
  mapUsed[(int)mm.buf] = mm;
  return mm.buf;
}


刚开始两圈没有问题,跑了两圈,就固定地出了问题,上层对一个内存的内容改变时,另外一个也随着改变了,一跟踪查看,发现两个内存的地址一样!而这两个内存地址正是通过函数CreateMm()返回的。
后跟踪进来查看,很容易就发现了问题所在。在上面的函数中的if语句中,使用&vecFree[index]返回了索引index节点的指针给pmm,然后加入到map中也没有问题,当vecFree.erase()一行一过,则pmm就变了,发现buf的地址不是通过&vecFree[index]取出来时的地址了,而是其后面的一条记录的地址了。所以,第一次调用CreateMm()时返回的是vecFree中的第3条记录的buf,本应该是第二条,但在erase()之后,就变成了第3条。接着再一次调用CreateMm()时,就把第二条记录返回了出来,而这条记录和前一次调用时的记录实际上是同一个,所以两次调用得到的内存地址是一样的。

注意第二次,因为这个空闲列表vecFree中只有3条记录,所以第二次调用时,erase并没有改变pmm原本取出来的内容。

知道了原来,对这个函数稍做修改即可:

char *CreateMm(int len)
{
  Smm *pmm = NULL;
  char *pret = NULL;     // 添加这一行
  int index = 0;
  if ( (index = search_in_free(len)) >= 0 )
  {
      pmm = &vecFree[index];
      pret = pmm->buf;                     // 添加这一行
      mapUsed[pmm->buf] = *pmm;            // 重新加入到正在使用的列表中
      vecFree.erase(vecFree.begin()+index);// 从空闲列表中删除
      return pret;      // 添加这一行
  }

  // 空闲列表中没有足够的内存,所以重新创建
  Smm mm;
  mm.buf = new char[len];
  mm.len = len;
  mapUsed[(int)mm.buf] = mm;
  return mm.buf;
}

如上,只添加了3行,直接记录当时的地址就行了。

以上的函数只是个大致流程,在实际代码中还需要进行其它的一些处理,比如分配的内存清空等操作,此处只做为流程上的演示。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值