IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 记录一次指针指向内存被修改的问题 -> 正文阅读

[C++知识库]记录一次指针指向内存被修改的问题

最近遇到了一个奇妙的问题,在一个抽奖活动里抽奖偶尔会出现发给客户端的数据不正确的情况,结果初步排查,发现这是由于有一个指针指向的对象里的数据发生了错乱。而且很奇妙的,经常是抽了好几十次才出现一次这种情况
先来看一段代码

const Item* OnePiece::getRandItem(Lib* pLib, const std::set<DWORD>& extraSet)
{

	std::vector<Item>& itemListCfg = pLib->itemList;

	std::vector<Item> itemList;
	DWORD totalWeight = 0;

	//初始化奖池
	std::vector<Item>::const_iterator iter = itemListCfg.begin();
	for (; iter != itemListCfg.end(); ++iter)
	{
		if (extraSet.count(iter->indexId) == 0)
		{
			//该奖品加入奖池
			itemList.push_back(*iter);
			totalWeight += iter->weight;
		}
	}
	//抽随机数
	DWORD tValue = 0;
	if (totalWeight > 0) {
		tValue = Tool::randBetween(0, totalWeight - 1);
	}

	DWORD maxTotalWeight = 0;
	const Item* pItem = NULL;
	iter = itemList.begin();
	for (; iter != itemList.end(); ++iter)
	{
		maxTotalWeight += iter->weight;
		if (tValue < maxTotalWeight)
		{
			pItem = &(*iter);
			break;
		}
	}

	return pItem;
}

该函数用于抽奖,用一个集合过滤掉不符合要求的奖品生成新的奖池并从这个新生成的奖池抽奖,函数最后返回一个指针。
这一段代码乍一看没啥问题,然而却隐藏着巨大的隐患。
原因在于vector执行push_back操作时会进行对象的拷贝。而itemList又是一个在函数里的局部变量,在离开这个函数的作用域之后,这个局部变量便脱离了作用域,而返回的指针又是存在这个vector里面的,这就会出现调用该函数的调用者拿到的指针指向一片非法区域!!! 那么为什么这种问题只是偶现,原因在于在离开了函数的作用域时,操作系统并不一定会马上会覆盖这片内存,所以大部分情况下这片内存指向的数据还是正确,但当操作系统将这块内存分配给其他变量后,那么这片内存可能就被修改了,这时如果我们再拿着原来的指向那块地址的指针去取数据,就可能会拿到一个奇怪的数据!
可以将上述代码修改如下:

const Item* OnePiece::getRandItem(Lib* pLib, const std::set<DWORD>& extraSet)
{

	std::vector<Item>& itemListCfg = pLib->itemList;

	std::vector<Item*> itemList;
	DWORD totalWeight = 0;

	//初始化奖池
	std::vector<Item>::iterator iter = itemListCfg.begin();
	for (; iter != itemListCfg.end(); ++iter)
	{
		if (extraSet.count(iter->indexId) == 0)
		{
			//该奖品加入奖池
			itemList.push_back(&(*iter));
			totalWeight += iter->weight;
		}
	}
	//抽随机数
	DWORD tValue = 0;
	if (totalWeight > 0) {
		tValue = Tool::randBetween(0, totalWeight - 1);
	}

	DWORD maxTotalWeight = 0;
	const Item* pItem = NULL;
	std::vector<Item*>::const_iterator it= itemList.begin();
	for (; it!= itemList.end(); ++it)
	{
		maxTotalWeight += *it->weight;
		if (tValue < maxTotalWeight)
		{
			pItem = *it;
			break;
		}
	}

	return pItem;
}
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-03-12 17:14:26  更:2022-03-12 17:16:08 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 4:41:06-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码