我对C/C++中的悬空指针感到有些困惑。
void remove(){
Node* curr = new Node(10);
Node* pt = curr;
delete curr;
// do something here
// do other thing here
}
我假设在函数remove()
终止之前,Node* pt
仍然是悬空指针?
在remove()
终止后,我不必担心指针Node* pt
?
我对C/C++中的悬空指针感到有些困惑。
void remove(){
Node* curr = new Node(10);
Node* pt = curr;
delete curr;
// do something here
// do other thing here
}
我假设在函数remove()
终止之前,Node* pt
仍然是悬空指针?
在remove()
终止后,我不必担心指针Node* pt
?
NULL
等是一种反模式。只要不对悬空指针进行解引用操作即可。remove
的注释部分,curr
和pt
都是悬空指针,因为它们都指向已被删除的对象。只要这段代码没有对它们进行解引用操作,就不会出现问题。当你调用 delete curr
时,存储在 curr
中的值不会改变,但是该位置的内存已经被返回给系统。
让我们逐行分析你的代码:
Node* curr = new Node(10);
为了举例说明,假设分配的内存地址为0x1000,这意味着curr
现在的值为0x1000
。
Node* pt = curr;
现在,pt的值(指向位置)为0x1000。
delete curr;
这将返回位于0x1000地址的内存给系统。但是,此时curr
和pt
仍然都包含值0x1000。
它们都是悬空指针。
当您使用原始指针时,悬空指针是不可避免的,并且它们并不是隐式的坏事。您只需要小心不要使用悬空指针或返回悬空指针即可。
void badfunc() {
char* p = new char[10];
delete p;
return p; // use of dangling pointer
}
关于你的问题:"我假设在函数remove()终止之前Node* pt仍然是悬挂指针?"
是的,在调用delete curr;
后,原先由Node* curr
和Node* pt
指向的内存块被释放。在调用delete curr;
之后不应该再使用curr
或者pt
的值(它们都有相同的值,并且无效)。不要假设调用delete
会改变curr
的值。它不会——你可以像这样在调用delete curr;
之前和之后打印出两个值来检查:
printf("%d, %d", curr, pt);
关于你的问题:"在remove()终止后,我不必担心指针Node* pt吗?"
确实如此,在remove()
完成后,Node* curr
和Node* pt
都不存在了。它们也超出了作用域(在remove()
之外不可访问)。因此,你不必担心它们。
此外,delete curr;
释放/销毁了先前由Node* curr
和Node* pt
指向的内存中的对象/数据,因此你也不必担心它。
有时候建议通过将悬挂指针设置为NULL来避免它们。这并不能解决问题,但如果你不小心使用这样的指针,它至少会清晰地表示出来。这是因为尝试取消引用NULL指针会导致内存分段错误——所以你至少可以得到一个可重现的运行时错误来查找你的错误。其他人说,盲目地将每个未使用的指针设置为NULL会使你的代码混乱不堪。在这里需要一些智慧来权衡利弊。
另一种方法是优先使用智能指针,但它们也有自己的陷阱。引用计数和标记-清除智能指针会将悬空指针转换为资源泄漏!而unique ptr没有安全的“观察者”指针类型。
局部指针在其作用域结束后就不存在了。它不能成为悬空指针,因为它不是指针。
pt
是此函数的本地变量;在控制流程离开函数后,您不必担心它。 - Beta