C++ 关于悬挂指针

如果一个地方指针既不为空,也没有被设置为指向一个已知的对象,则这样的指针称为悬挂指针。在程序里面是很危险的事

,代码如下:

#include "stdafx.h" #include "iostream" using namespace std; //typedef string t; void f(int *p); int main() { //int a = 10; int *i; //i = &a; f(i); cout<<*i; return 0; } void f(int *p){ cout<<p; if(p!=0) *p = 100; }

当控制函数执行到f()中时候,f()不能判断指针的合法性,将会产生很严重的错误。(但是编译通过)

最好的解决方法是指针声明时候,同时赋予其指向一个对象 即去掉注释部分

### C++ 类中指针悬挂问题及解决方法 #### 什么是悬挂指针? 在 C++ 中,当一个指针指向的对象被删除或超出作用域后,该指针仍然持有原来的地址,这种状态被称为 **悬挂指针** 或者 **野指针**。尝试通过这样的指针访问内存可能会引发未定义行为[^1]。 #### 悬挂指针的成因 悬挂指针通常由以下几种情况引起: 1. 局部变量的作用域结束之后返回其地址。 2. 动态分配的内存被 `delete` 后,指针仍保留原值。 3. 多个指针共享同一块动态分配的内存,在其中一个指针调用 `delete` 后其他指针成为悬挂指针。 例如,以下代码展示了局部变量引起的悬挂指针问题: ```cpp int* createInt() { int value = 5; int* ptr = &value; // 创建了一个指向局部变量的指针 return ptr; // 返回指向已经销毁的局部变量的指针 } ``` 在此例子中,`createInt()` 函数返回的是栈上的局部变量地址,而这个地址会在函数退出时失效,因此外部接收到的指针成为一个悬挂指针[^1]。 #### 解决方案一:避免返回局部变量的地址 可以通过将数据存储到堆上来解决问题。如下所示: ```cpp int* createIntHeap() { int* ptr = new int(5); // 使用new操作符创建堆上的整数 return ptr; // 正确返回堆上分配的数据 } void cleanup(int* p) { delete p; // 记得清理资源 } ``` 这种方式解决了由于栈上临时对象消亡带来的隐患,但是需要注意手动管理内存以防止泄漏[^3]。 #### 解决方案二:使用智能指针 现代 C++ 提供了自动管理生命周期的功能——即标准库中的智能指针 (`std::unique_ptr`, `std::shared_ptr`) 来替代原始裸指针。这些工具能够有效减少甚至消除悬空指针的风险。 示例采用 `std::unique_ptr` 的版本: ```cpp #include <memory> std::unique_ptr<int> createIntSmart() { auto uptr = std::make_unique<int>(5); return uptr; // unique_ptr 自动处理所有权转移 } ``` 此实现无需显式的释放逻辑,因为一旦离开作用范围或者复制给别的容器实例时,内部机制会负责安全回收关联资源[^4]。 #### 解决方案三:重载拷贝构造函数与赋值运算符 如果类中含有动态分配的成员,则需要特别注意深浅拷贝的区别。默认情况下,编译器生成的拷贝构造函数只会做表层副本(shallow copy),这意味着两个不同对象可能共同拥有同一个实际物理位置作为某些字段的内容载体;一旦其中一方销毁自身携带的信息结构,另一方便陷入危险境地。 考虑下面的例子: ```cpp class MyClass { public: char* data; MyClass(const char* str){ size_t len = strlen(str)+1; data = new char[len]; strncpy(data,str,len-1); data[len-1]='\0'; } ~MyClass(){ delete []data; } }; ``` 如果没有自定义拷贝控制功能,那么像这样简单的声明将会造成潜在风险: ```cpp MyClass objA("hello"); MyClass objB=objA;// 默认进行了浅拷贝 // 当objA先于objB析构时,objB.data变成了悬挂指针 ``` 为此应该重新定义相应的特殊成员函数来确保深层克隆发生: ```cpp MyClass& operator=(const MyClass& other){ if(this!=&other){ delete[] data; size_t len=strlen(other.data)+1; data=new char[len]; strncpy(data,other.data,len-1); data[len-1]='\0'; } return *this; } MyClass(const MyClass& other):data(nullptr){ size_t len=strlen(other.data)+1; data=new char[len]; strncpy(data,other.data,len-1); data[len-1]='\0'; } ``` 以上措施可以保障即使存在多个引用也不会互相干扰彼此所依赖的实际资料区域[^5]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值