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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值