子列表使用std :: shared_ptr,以便节点保存在内存中至少与父节点一样长.但是我不想让一个节点拥有它的父母,所以我使用weak_ptr作为父母的指针.
但是,算法存在问题.一个算法必须从weak_ptr创建一个新的shared_ptr,所以我不能直接使用operator ==,并且使用标准函数(如std :: find())需要编写一个名为my_weak_ptr.lock()的lambda函数,然后比较它到一些shared_ptr.
如果我切换到shared_ptr,代替节点删除的代码中的任何小错误都可能导致内存泄漏.或者如果我有一个指向已经删除的节点的指针,代码将能够访问不应该存在的节点,因此发现一些错误可能会变得更加困难.但是使用shared_ptr与weak_ptr一样安全,因为不取消引用/删除/ etc.当不应该(因为它比原始的C指针好)和std :: find()可以直接使用,因为shared_ptr可以被取消引用,不像weak_ptr.
这里是否有“更好”的设计,或者这是具体情况的一个问题,这取决于例如如果我执行了weak_ptr :: lock()的额外操作,还是冒着难以发现的错误的风险呢?
解决方法
你说你的算法必须锁定weak_ptr – 我希望有所不同.这些算法必须从节点获取一个父类shared_ptr.锁定父级的weak_ptr是节点的任务,并将结果返回给父节点或NULL.
这是一个实现细节,节点将他们的父节点存储为shared_ptr或weak_ptr.仅通过向任何客户端提供shared_ptrs来封装该细节.
class Node { /* ... */ std::weak_ptr<Node> parent; public: std::shared_ptr<Node> getParent() { return parent.lock(); } };
编辑:
当然,概念上同样适用,如果有不止一个父母.
EDIT2:
在评论中,您提到的算法遍历您的父母列表,使得有必要为每个算法编写lambdas.如果您经常使用这些算法,请考虑编写一个自动锁定目标weak_ptr并返回一个shared_ptr的迭代器适配器:
template <class WPIterator> struct LockTheWeakIterator { //static_assert that WPiterator's value_type is some weak_ptr //typedef all those iterator typedefs typedef typename WPIterator::value_type::element_type element_type; shared_ptr<element_type> operator*() { return iter->lock(); } //provide all the other operators - boost.operators might help with that... WPIterator iter; }; template <class IT> LockTheWeakIterator<It> lockTheWeak(It iter); //somewhere... auto theParentIter = std::find_if(lockTheWeak(parents.begin()),lockTheWeak(parents.end()),whatIAmLookingFor);