关于野指针

本文探讨了多线程环境下避免野指针的策略,详细解释了野指针的概念及其产生的可能性,并提供了两种解决方案:一种是退出线程时不执行删除操作,而是每次调用网络循环时检测变量是否存在后进行删除;另一种是在删除操作完成后设置状态变量,通过子线程循环检测以确保完全关闭后再执行删除操作。文章旨在帮助开发者理解并预防这类常见的内存管理错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

所谓的野指针,实际上就是指针内存释放了之后,还继续调用,然后造成堆破坏。

这样的错误在刚开始是检测不出来的,只有在New的时候进行堆检测才会检测出来。


下面是我遇到的一个野指针,很隐蔽。只是有概率的出现野指针。

这是一个多线程的问题,首先在主线程进行removeSocket(),正常情况下,removeSocket会执行break,子线程是一个循环

				while (getNowSocket() && getNowSocket()->GetSocketStatus()==SOCKET_STATUS_CONNECT)
				{
					if(this->getNowSocket()->OnSocketNotifyRead() == -1)
					{
						break;
					}
				}

下面是removeSocket的方法

//移除套接字
	void removeSocket(){ 
		if(m_pSocket != NULL)
		{
			if(m_pSocket->GetSocketStatus()==SOCKET_STATUS_CONNECT) 
			{
				m_pSocket->CloseSocket(); 
			}
                        if(m_pSocket != NULL) CC_SAFE_DELETE(m_pSocket);
		}
	};


也就是会调用removeSocket来delete socket;

这样做是十分危险的,因为虽然在循环里调用了break进行清除,但是由于网络的不确定性,很可能在你清除Socket的时候,刚好运行到循环判断的时候,这样就造成了野指针,然后程序崩溃。所以delete socket可以转到线程结束的时候调用。



9.17补充:

其实上面所说的并非是真正造成野指针的原因,真正的原因还在多线程的使用,主线程调用removeSocket是执行关闭Socket,但是在关闭的某一时刻子线程就已经知道主线程要关闭Socket了,就会自动执行关闭代码,如果照原来的写法,在线程结束的时候调用,也有可能在线程结束的时候removeSocket没有执行完,造成野指针。


下面是给出的解决方法,有两种:

1.退出的线程并不执行delete操作,每次调用网络循环子线程的时候检测变量是否存在,如果存在就delete

2.做一个状态变量,当removeSocket执行完成的时候状态设为完全关闭,在子线程中使用循环检测,如果没有完全关闭,则循环等待,如果完全关闭则delete


第一种方法简单方便,第二种方法逻辑上略复杂,而且略代码冗余。

但是第二种方法可以及时释放内存,使用哪种方法就见仁见智咯。

### 指针的概念 指针是指向一个未知或非法内存位置的指针。这种指针可能指向已被释放的内存区域,或者是未被初始化的随机地址[^1]。由于其行为不可预测,因此被称为“”。具体来说,指针主要分为以下几种情况: - **未初始化的指针**:声明了一个指针变量但未对其进行初始化,此指针会持有随机值并指向不确定的内存位置[^2]。 - **越界访问**:当通过指针访问数组超出有效索引范围,则可能会导致指针变为指针[^4]。 - **已释放内存上的指针**:如果某个动态分配的空间已经使用 `free` 或者 `delete` 进行销毁,而对应的指针仍然保留着原来的地址值,那么此指针就成为了指针[^3]。 ### 如何处理指针? 为了避免因指针引发的各种错误,在实际编码过程中应当采取一些预防措施: #### 初始化指针 在定义任何类型的指针之前都应该给予合理的初始值。通常情况下可以选择将它们设为空(`NULL`)或者其他安全默认对象作为目标[^3]: ```c++ int* ptr = nullptr; ``` #### 删除后的重置 每当调用了删除操作符 (`delete`, `free`) 来回收由新运算符 (`new`, `malloc`) 所创建的对象之后, 应立即将相应的指针赋值为零(null), 确保不会再次误用这些悬空指针[^3]: ```cpp if(ptr != nullptr){ delete ptr; ptr = nullptr; } // 对于C标准库中的 malloc/free 可以这样做: #define SAFE_FREE(p) do { if ((p)) { free((p)); (p)=nullptr; }} while(0) SAFE_FREE(myPointer); ``` #### 使用现代技术替代传统裸露型别的管理方式 考虑采用更高级别的抽象工具比如智能指针(Smart Pointers),容器类(Container Classes)等来自动生成资源生命周期控制逻辑从而减少人为失误几率[^3]: ```cpp #include <memory> std::unique_ptr<int> uptr(new int()); ``` 以上策略能够有效地降低甚至消除指针所带来的风险隐患。 ### 总结 综上所述,理解并掌握关于指针的知识对于提高软件质量和稳定性至关重要。通过对指针的良好实践——包括但不限于始终初始化每一个新建实例、及清理不再使用的实体并将关联引用清零以及积极拥抱现代化解决方案如RAII模式下的自动存储管理手段等等都可以显著改善这一领域内的常见难题状况。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值