我目前正在研究最流行的智能 Ptr 实现,例如 boost 共享指针和弱指针以及 loki 智能和强指针,因为我想实现自己的,并且根据我的理解,Loki 强指针对我来说看起来不安全,但我宁愿我认为我的理解有误,所以想讨论一下它是否安全。我认为它不安全的原因是,据我所知,它没有足够小心地对待弱指针(即 StrongPtr,其中 false 表示其弱):
例如解引用函数:
PointerType operator -> ()
{
KP::OnDereference( GetPointer() ); //this only asserts by default as far as i know
//could be invalidated right here
return GetPointer();
}
在多线程环境中,弱指针可能随时失效,因此该函数可能返回失效的 Ptr。
据我的理解,您要么必须为要取消引用的 ptr 创建一个 StrongPtr 实例,以确保它不会在中途失效。我认为这也是为什么 boost 不允许您在不先创建共享_ptr 实例的情况下取消引用weak_ptr 的原因。我认为 Lokis StrongPtr 构造函数也遇到同样的问题。
这是一个问题还是我读错了 src?
关于
assert
的使用,在空的operator->
实例上使用StrongPtr<>
是一个编程错误;即,在取消引用之前确保
StrongPtr<>
实例非空是调用者的责任。为什么除了
assert
之外还需要其他东西?也就是说,如果您认为其他行为比assert
更合适,那么这正是该政策的目的。
这是前置条件和后置条件的根本区别;这里有一个关于这个主题的很长但非常好的线程:comp.lang.c++.moderated: Exceptions。请特别阅读 D. Abrahams 的帖子,他详细解释了我所说的理解事实。 ;-]
关于
StrongPtr<>
的线程安全,我怀疑 Loki 的大部分内容早于任何严重的线程安全问题;另一方面,boost::shared_ptr<>
和std::shared_ptr<>
明确地保证是线程安全的,所以我确信它们的实现为研究提供了“更好”(尽管更复杂)的基础。
仔细阅读后,我想我明白了其中的道理。
StrongPtr
对象是双重的,因为它们同时代表 Strong
和 Weak
引用。
assert
的机制在Strong
版本上效果很好。在 Weak
版本中,调用者有责任确保引用的对象存活得足够长。这可以通过以下任一方式实现:
Strong
版本Strong
实例std::shared_ptr
的好处是,当您已经知道该项目将超过您的使用期限时,您可以避免创建新对象。这是一个有争议的设计决策,但对于专家来说效果很好(Alexandrescu 无疑是其中之一)。它可能不是针对普通用户(我们)的,恕我直言,强制采用 Strong
版本会更好。
也有人可能会说,事后诸葛亮的批评总是更容易。
Loki
,尽管它很伟大,但它已经很古老了。