【发布时间】:2020-07-24 15:03:31
【问题描述】:
当一个对象有一个指针成员时,指针可能指向不属于该对象的那部分内存。因此,它可能会在不通知对象的情况下被释放并导致指针悬空(以及大量的调试问题)。例如,假设我有一个 ClassHasPointer 类型的对象,它有一个 AnotherClass * 类型的成员变量 m_memberPtr。
class ClassHasPointer
{
public:
void setMember(AnotherClass* anotherObj) { m_memberPtr = anotherObj; }
AnotherClass* getMember() { return m_memberPtr; }
private:
AnotherClass* m_memberPtr = nullptr;
}
现在假设我有一个名为 anotherObj 的 AnotherClass 对象,我已经在程序的其他地方定义并使用了它。现在,我决定初始化一个ClassHasPointer的对象:
ClassHasPointer A;
A.setMember(&anotherObj); // m_memberPtr points to anotherObj
现在,如果 anotherObj 超出范围或在程序的任何部分被释放,则 m_memberPtr 指向垃圾,因此它是一个悬空指针:
AnotherClass* aBadPtr = A.getMember(); // anotherObj was destroyed, dangling pointer!
我们倾向于在类中经常使用指针作为成员变量。我认为每次我们这样做时,都会附带一个警告,即该类可能不拥有它所指向的数据。我的问题是,我们如何确保在数据被释放时不访问数据,而不必不必要地复制它指向的数据?更重要的是,一般而言,避免这种陷阱的良好做法/指南/设计模式是什么?
编辑:我知道我们可以使用智能指针,例如std::shared_ptr,但只有在堆上定义了另一个Obj 时才能使用(例如AnotherClass* anotherObj = new AnotherClass())。如果不是这种情况,我无法改变怎么办?还有其他方法可以解决悬空指针问题吗?
【问题讨论】:
-
std::shared_ptr不是一个选项,因为...? -
shared_ptr 是你的朋友,会在漆黑的夜晚保护你免受恶魔的伤害
-
好点@ZuodianHu。请参阅编辑。
-
@nmnm 我不相信悬空指向堆栈对象的指针有一个通用的答案,除了正确嵌套你的范围(例如,只指向堆栈对象之前将自动清理的对象)指向对象;在指向对象之后声明的堆栈对象等)。这是一个设计问题。对不起。
-
如果不是这种情况,我无法改变它怎么办? -- 好吧,你的设计依赖于客户端来确保指针具有范围大于
A。
标签: c++ class pointers design-patterns dangling-pointer