std::list什么情况下会出现error的错误?

red-fly 2016-03-07 07:27:16
为了对内存的管理,使用了std模板,定义了两个变量:

map<int, mem_s_info> m_mapMemBusyList; // 正在使用的内存列表,key为内存地址
list<mem_s_info> m_vecMemFreeList;

m_mapMemBusyList用来保存正在使用的内存,m_vecMemFreeList保存未被使用的内存。
其中结构mem_s_info定义如下(这个结构本身可以不用去关心它):

struct mem_s_info
{
char *pszBuf; // 内存地址
int len; // 内存长度
int id; // 内存的标示号,暂时没什么用处
__time64_t ttCreate; // 创建时间
__time64_t ttAccess; // 最后一次访问时间,即被重新利用的时间

#ifdef _DEBUG
mem_ins_info memIns; // 用于保存分配该内存的代码信息
#endif
};

流程如下:
在要分配一个内存时,首先从m_vecMemFreeList中查找是否有对应长度的空闲内存,如果有,就把它从m_vecMemFreeList中移到m_mapMemBusyList中,如果没有,则分配一个新的,然后加入到m_mapMemBusyList中。代码如下:

char *CMemoryManagerS::CreateMem( const int len, const char* file /*= NULL*/, const char *function /*= NULL*/, const int line /*= 0*/ )
{
if ( len < 0 || len > 0x4000000 )
return NULL;

// 如果为0,则也分配8个字节
int startlen = len;
if ( len == 0 )
startlen = 1;

mem_s_info *pstuSInfo;
char *pReturnPtr = NULL;
list<mem_s_info>::iterator iterFree;
CAutoCri criFree( m_csMemBusy);
for ( iterFree = m_vecMemFreeList.begin(); iterFree != m_vecMemFreeList.end(); iterFree++ )
{
pstuSInfo = &(*iterFree);
if ( pstuSInfo->len <= startlen )
continue;

if ( pstuSInfo->len > startlen * 5/4 && pstuSInfo->len >= 32 )
{
// 比需求内存大的最小内存,比需求内存大了1/4,所以为了节约,重新进行申请,防止过分地浪费内存。
break;
}

// 搞定
pstuSInfo->ttAccess = _time64(NULL);
memset( pstuSInfo->pszBuf, 0, pstuSInfo->len );

// 把此条记录移到使用列表中
pReturnPtr = pstuSInfo->pszBuf;
#ifdef _DEBUG
SetMemIns( pstuSInfo, file, function, line );
#endif
m_mapMemBusyList[(int)pReturnPtr] = *pstuSInfo;
m_vecMemFreeList.erase( iterFree );
return pReturnPtr;
}
criFree.Release();

// 需要分配新的内存。弄成8字节对齐,估计运行的效率会高一些
int irelen = startlen + 8; // 不是+7,目的是要使分配出来的内存一定比实际指定的要大,最多大8个字节,最少大1个字节
irelen /= 8;
irelen *= 8;

mem_s_info stuSInfo;
stuSInfo.pszBuf = new char[irelen];
stuSInfo.len = irelen;

CAutoCri criCounter( m_csIDCounter );
stuSInfo.id = m_memIDCounter++;
criCounter.Release();

stuSInfo.ttCreate = _time64(NULL);
stuSInfo.ttAccess = stuSInfo.ttCreate;
if ( stuSInfo.pszBuf == NULL )
{
return NULL; // 分配失败
}

memset( stuSInfo.pszBuf, 0, stuSInfo.len );
#ifdef _DEBUG
SetMemIns( &stuSInfo, file, function, line );
#endif
CAutoCri criBusy2( m_csMemBusy );
m_mapMemBusyList[(int)stuSInfo.pszBuf] = stuSInfo;
criBusy2.Release();

return stuSInfo.pszBuf;
}


在删除时,直接把要删除的从m_mapMemBusyList中移到m_vecMemFreeList中即可,代码如下:

UINT32 CMemoryManagerS::DeleteMem( const char *pmemAddress )
{
map<int, mem_s_info>::iterator iter;
list<mem_s_info>::iterator iterFree;
mem_s_info memInfo = {0};

CAutoCri criBusy( m_csMemBusy);
iter = m_mapMemBusyList.find( (int)pmemAddress );
if ( iter == m_mapMemBusyList.end() )
{
return errorcode_MEM_DELETEALREADY;
}

// 把它从使用表中移到未使用的列表中,并修改访问时间
memInfo = iter->second;
memInfo.ttAccess = _time64(NULL);
m_mapMemBusyList.erase( iter );
cntBusy = m_mapMemBusyList.size();

// 注意,必需先使用,然后再删除。注意必需按照从小到大的顺序插入进去

iterFree = m_vecMemFreeList.begin();
while ( iterFree != m_vecMemFreeList.end() )
{
if ( iterFree->len < memInfo.len )
{
iterFree++;
continue;
}
break;
}
m_vecMemFreeList.insert( iterFree, memInfo );

criBusy.Release();
ShinkList(); // 这一行用于删除m_vecMemFreeList中停留时间过长的那些内存,在出问题时此代码未生效,所以本贴说的问题和此函数无关
return errorcode_SUCCESS;
}


环境:vs2010,所以在变量窗口中可以看到ma和list的各项状态,正常情况如下:

m_vecMemFreeList [0] 结构mem_s_info的各字段值
[1] 结构mem_s_info的各字段值
[2] 结构mem_s_info的各字段值
[3] 结构mem_s_info的各字段值
... ...


失败时如下的形式:

m_vecMemFreeList [0] 结构mem_s_info的各字段值
[1] 结构mem_s_info的各字段值
[2] 结构mem_s_info的各字段值
[error]
[error]
[error]
... ...

注意,实际的数量有很多,即那些error都是在m_vecMemFreeList的有效个数以内。
初步认为很可能是内存越界导致的,但还不确定
大伙帮忙看下是什么问题导致的,如何定位这种问题
...全文
224 7 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
redui 2016-03-08
  • 打赏
  • 举报
回复
用vector保存指针,指针根据实际情况分配内存,如果需要按照从小到大排序,直接用stl的sort函数即可。 其实不管用那种方式,有两个原则:一是内存集中在一个地方管理(分配和释放);二是一个数据只分配一次内存,不要出现分配多次和数据复制的情况发生,其它使用和搜索请使用指针
gz_qmc 2016-03-08
  • 打赏
  • 举报
回复
在用对的情况不会
red-fly 2016-03-08
  • 打赏
  • 举报
回复
引用 3 楼 oyljerry 的回复:
是不是对list等有多线程访问操作等,是否有加锁保护
是多线程访问,有加锁: CAutoCri criFree( m_csMemBusy);
oyljerry 2016-03-08
  • 打赏
  • 举报
回复
是不是对list等有多线程访问操作等,是否有加锁保护
red-fly 2016-03-08
  • 打赏
  • 举报
回复
问题解决,经过多次测试没有发现这个问题了。 这个内存管理的类本身没有问题,是另外的代码有一个内存长度变量没有初始化,但用它分配的内存似乎有问题,好像越界了,导致不确定性的内存覆盖,结果总是表现在上面贴出来的内存管理类上。 当然这个内存管理的类,可以再根据实际情况进行改进,使效率提升
red-fly 2016-03-07
  • 打赏
  • 举报
回复
引用 1 楼 redui 的回复:
你这样内存复制来复制去的太乱太麻烦,应该专门使用一个数组来存放结构体,然后用map和list保存指针,用来指示已用的和空闲的,其实只要保存已用的就够了,不在容器里面的指针说明是空闲的。或者不用指针,用数组的索引标识是否已用
数组的个数不固定,而且变化范围比较大,另外就是每个项所对应的内存长度也不固定,范围很广,从几十字节到几MB字节。如果采用数组,那可能会经常有删除、添加等操作,相当不方便。 不在容器中说明是空闲的,那确实,所以这里有两个容器,一个是map,装“忙”的内存,这样在删除时可以直接找到,另外一个是list装从小到大排列的空闲项
redui 2016-03-07
  • 打赏
  • 举报
回复
你这样内存复制来复制去的太乱太麻烦,应该专门使用一个数组来存放结构体,然后用map和list保存指针,用来指示已用的和空闲的,其实只要保存已用的就够了,不在容器里面的指针说明是空闲的。或者不用指针,用数组的索引标识是否已用
代码静态分析工具PC-LINT安装配置 PC-Lint是C/C++软件代码静态分析工具,你可以把它看作是一种更加严格的编译器。它不仅可以检查出一般的语法错误,还可以检查出那些虽然符合语法要求但不易发现的潜在错误。 C语言的灵活性带来了代码效率的提升,但相应带来了代码编写的随意性,另外C编译器不进行强制类型检查,也带来了代码编写的隐患。PCLint识别并报告C语言中的编程陷阱和格式缺陷的发生。它进行程序的全局分析,能识别没有被适当检验的数组下标,报告未被初始化的变量,警告使用空指针,冗余的代码,等等。软件除错是软件项目开发成本和延误的主要因素。PClint能够帮你在程序动态测试之前发现编码错误。这样消除错误的成本更低。 使用PC-Lint在代码走读和单元测试之前进行检查,可以提前发现程序隐藏错误,提高代码质量,节省测试时间。并提供编码规则检查,规范软件人员的编码行为。 由于PC-LINT对于一般程序员来说可能比较陌生,有好多人安装了也不知道怎样配置和使用。 下面我就根据自己的安装和配置心得对PC-Lint的安装、配置及使用进行下详细说明.本人主要介绍了将PC-Lint集成到VC++6.0和SourceInsight的方法和步骤。 (一)Windows下C/C++开发工具中,VC6使用较为普遍,因此这里先讲下VC6.0环境中集成pclint的步骤. 首先, 当然要下载软件,正版软件要200多$呢,买不起!所以只好网上找免费的拉。从http://www.61ic.com/down/othe/pclint.rar处可以下载到一个8.0版本的pclint. 1.将pclint.rar解压至c:\, 这样lint文件就位与c:\pclint(安装目录)下了。 2.将c:\pclint\lnt 下的3个文件lib-w32.lnt,env-vc6.lnt,co-msc60.lnt拷贝至c:\pclint下, 再在安装目录下创建std.lnt和options.lnt两个文件,其中std.lnt的内容如下 // contents of std.lnt c:\pclint\co-msc60.lnt c:\pclint\lib-w32.lnt c:\pclint\options.lnt -si4 -sp4 -i"D:\Program Files;D:\Program Files\Microsoft Visual Studio\VC98\Include" //end 其中-i后面的路径名为VC的安装路径和VC Include 文件路径,根据自己的修改便可。 options.lnt 内容可为空,为定制内容,以后需要时再添加。 准备工作做完了,下一步就是要将pclint集成到VC6中去,先配置lint使之能对单个C或C++文件进行检查。 1.打开VC6,tools--->customize-->tools 新建一个名为pclint的项,在下面填入 command: C:\pclint\lint-nt.exe arguments: -u c:\pclint\std.lnt c:\pclint\env-vc6.lnt "$(FilePath)" Use Output Window 打上勾 close 完成。 这个在你VC窗口tools菜单下应该多了一个pclint选项,可以用它来运行lint程序,对你的c/c++代码进行静态检查了。 现在就可以用个小程序测试一下pclint了 //test1.cpp #include class X { int *p; public: X() { p = new int[20]; } void init() { memset( p, 20, 'a' ); } ~X() { delete p; } }; 编译这个文件,看下你的编译器给你多少警告,再运行下lint, 可以自己对比一下。 我的机器上,VC产生0 errors 0 warnings, 而lint程序产生了如下8条警告信息,有些还是很有用处的提示,这里就不一一分析了. test.cpp(12): error 783: (Info -- Line does not end with new-line) test.cpp(7): error 1732: (Info -- new in constructor for class 'X' which has no assignment operator) test.cpp(7): error 1733: (Info -- new in constructor for class 'X' which has no copy constru

16,548

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • AIGC Browser
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧