C++之迭代器失效及解决
描述
在霍尼韦尔门禁项目中,通过遍寻霍尼韦尔设备获取设备信息后,GotMessage会不断收到消息,并把消息数据添加到容器里面。在回调函数线程中,循环获取容器数组中的数据进行处理,并需要删除尾部数据。存储数据的容器的实现,需要考虑到频繁的插入和删除数据。
综合来说,CStringList和链表式容器List是最好的实现方式,但频繁的插入和删除数据,会造成迭代器失效的问题。
基于CStringList来实现数据插入删除
实现逻辑描述
采用CStringList来实现频繁的数据插入和删除操作。从头部插入数据,从尾部删除数据。
代码实现
//1、定义类变量
CStringList m_szListInput;
//2、初始化;
m_szListInput.RemoveAll();
//3、CStringList从头部添加数据元素。
//(遍历所有霍尼韦尔设备后,GotMessage会不断收到消息,并把消息数据添加到CStringList变量里面)
m_szListInput.AddHead(CString(bstrTranInfo));
//4、启动线程函数ClientThread,进行数据处理,并删除尾部数据。
DWORD WINAPI ClientThread(LPVOID lpParam)
{
CVCClientDlg* pParent = (CVCClientDlg*)lpParam;
while(1)
{
if(! (pParent->m_pCallback->m_szListInput.IsEmpty()) )
{
CString szTemp;
//尾部删除数据,并去除数据元素内容
szTemp = pParent->m_pCallback->m_szListInput.RemoveTail();
}
else
{
Sleep(1000);
}
}
}
崩溃界面显示
分析
网上找相关例子很少,可如下参考:
多线程中使用CStringList出现问题
相关解决方案很少,对于频繁插入删除的场景来说,故采用其他方案来实现。STL链表式容器List来实现相似的处理。
基于链表式容器List来实现数据存储
代码实现
//list定义
std::list<wchar_t*> m_szDataList;
//初始化及类的析构函数,需要清空,释放内存
m_szDataList.clear();
//仍采用头部添加数据。
m_szDataList.push_front(CString(bstrTranInfo).AllocSysString());
//线程回调函数中,处理数据,获取并进行尾部删除数据。
DWORD WINAPI ClientThread(LPVOID lpParam)
{
CVCClientDlg* pParent = (CVCClientDlg*)lpParam;
while(1)
{
if (!(pParent->m_pCallback->m_szDataList.empty()))
{
CString szTemp;
szTemp = pParent->m_pCallback->m_szDataList.back();
pParent->m_pCallback->m_szDataList.pop_back();
}
}
崩溃问题描述
从代码跟进看,list容器中储存的数据是正常的,获取尾部数据出现崩溃,显然是操作的指针不对。
错误分析
错误提示:“list iterator not decrementable”
List迭代器指针不能进行递减了,此时迭代器处于失效状态。
网上关于错误描述:
在开始处理的时候正常运行,运行一段时间之后会出错:list iterator not dereferenceable
原因:
iterator 会错误
你用 了iterator以后,只能自己保证 iterator 没问题
因为你在 频频使用删除操作
这个操作通常会使 iterator 失效
关于迭代器失效总结
1、对于关联式容器(map, list, set)元素的删除,插入操作会导致指向该元素的迭代器失效,其他元素迭代器不受影响。
2、对于顺序式容器(vector)元素的删除、插入操作会导致指向该元素以及后面的元素的迭代器失效。
解决方案:
void DataDealProcess(CVCClientDlg* pVCClient, CString szTemp)
{
if (pVCClient == nullptr || szTemp.IsEmpty())
return;
//处理逻辑
//..................
}
DWORD WINAPI ClientThread(LPVOID lpParam)
{
CVCClientDlg* pParent = (CVCClientDlg*)lpParam;
while(1)
{
if (!pParent->m_pCallback->m_szDataList.empty())
{
std::list<wchar_t*>::iterator it = pParent->m_pCallback->m_szDataList.begin();
while (it != pParent->m_pCallback->m_szDataList.end())
{
if (*it)
{
CString szTemp = *it;
std::list<wchar_t*>::iterator cur = it;
++it;
pParent->m_pCallback->m_szDataList.erase(cur);
DataDealProcess(pParent, szTemp);
}
else
{
++it;
}
}
}
else
{
Sleep(1000);
}
}
return 1;
}
网络资料参考
1、STL容器中 存放指针与对象区别 遍历删除与释放操作
https://blog.csdn.net/ac_huang/article/details/29382629
2、C++之迭代器失效及解决
https://blog.csdn.net/Yinghuhu333333/article/details/80744440