1 现象:问题描述
在XXX版本中,进程A在对多个连接结点的数据进行处理时,一旦有结点数据处理完成,程序就出现core dump,报段违规错误
2 关键过程:根本原因分析
通过分析core文件发现,程序访问的内存非法,程序访问动态数组CArray中元素非法,我们看看STTask的定义:
struct STTask
{
CString m_Name;
void* m_Keeper;
….
};
STTask * CreateTask(STTask & task)
{;
…
NEW(task.m_Keeper, char[TASK_KEEPER_LEN]);
…
return task;
}
在STTask构造时会分配一片内存给m_Keeper用于任务缓存。
那么当多个任务时,我们将一个新的结点加入CArray中,这时我们看看CArray的操作:
void CArray::AddToTail(T & data_)
{
.....
*(m_pArrayEnd) = data_;
....
}
*(m_pArrayEnd) = data_; data_是需要加入的结点数据,这时CArray实际是使用STTask的operator=操作进行赋值,但是STTask没有重载operator=操作,C++默认采用位拷贝(bitcopy)对对象进行赋值,这样导致CArray中的结点只是简单COPY了指针本身,而没有COPY其指向的内容,这样两个结点的m_Keeper同时指向一块缓存,当一个结点处理结束后会释放此缓存,那么第二个结点通过m_Keeper使用缓存时当然非法访问了内存
3 结论:解决方案及效果
解决方法是重载STTask的operator=方法,阻止编译器简单的进行bitcopy;
4 经验总结:预防措施和规范建议
1 在类设计时一定要注意对象复制(赋值)的影响,特别是对于类中含有指针的情况,
2 需要注意通过编写适合的拷贝构造函数和赋值函数来阻止简单的位拷贝行为
5 备注
N/A
6 考核点
缺省位拷贝构造器。
7 试题
1 关于如下代码说法正确的是:A
struct STTask
{
…
CString m_Name;
void* m_Keeper;
….
~ STTask
{
If ( m_Keeper != NULL )
{
delete m_Keeper;
}
}
};
STTask getTask()
{
STTask a;
NEW(a.m_Keeper, char[100]);
…
return a;
}
main()
{
STTask a = getTask();
printf("a.m_Keeper=%s", a.m_Keeper);
}
A ) getTask 调用返回的临时类STTask 在语句STTask a = getTask();
后就析构了,将其指针m_keeper 释放从而导致拷贝自此临时变量的变量a的m_keeper为野指针。
B)getTask的 申请的空间没有释放。
C)以上代码没有问题(不考虑编程规范)
D)结构STTask中定义的函数~ STTask没有定义为public,导致没有调用析构器释放空间
阅读(245) | 评论(0) | 转发(0) |