假设“B-things”的寿命不超过“它们都有一个指向的大对象”,那么当“大对象”被删除时,你就不会有一个悬空指针。
如果“A 类的一个实例”将这两个对象都作为数据成员,那么它们将同时被销毁(嗯,与它们在类中声明的顺序相反,但接近于同时) , 所以确保悬空指针永远不会被使用应该是相当容易的。
另一方面,如果你随意传递指向“大对象”的指针,将它们存储在生命周期未知的各种不同的地方,然后删除“大对象”——当然,这是一个禁忌。问题是“不择手段”——您需要保持控制并确保大对象比指向它的对象寿命长。
例如,以下是完全安全的:
struct Big {
// big stuff
};
struct Little {
Little(const Big *a) : bigthing(a) {}
// stuff that uses bigthing
private:
const Big *bigthing;
};
struct Foo {
Big onlybigthing;
Little firstlittlething;
Little secondlittlething;
Foo() :
onlybigthing(),
firstlittlething(&onlybigthing),
secondlittlething(&onlybigthing)
{}
};
当然,前提是 的实例Little
不会将其指向Big
, 的指针分发给任何来请求它的人,然后将其存储在Foo
对象的生命周期之外。同样Foo
必须避免将实例的副本分Little
发给可能存储这些实例的人(以及与它们一起的指针)。
但是你说你的类 A 有两个成员,而这里我有三个(一个Big
和两个Little
),因为你还说你创建了这两个对象的三个实例。我不明白那是什么意思。
这是另一个安全的例子:
int main() {
Big big;
Little little1(&big);
Little little2(&big);
}
这是安全的第三个示例:
struct Little {
Little(const std::shared_ptr<Big> &a) : bigthing(a) {}
// stuff that uses bigthing
private:
std::shared_ptr<Big> bigthing;
};
int main() {
std::shared_ptr<Big> big(new Big());
Little little1(big);
Little little2(big);
big.reset(); // release our shared ownership
// safely do stuff using little1 and little2
return 0;
// on exit, little2 is destroyed first, then when little1 is destroyed
// it releases the last shared ownership of the instance of `Big`,
// which is destroyed.
}