【问题标题】:What's correct way to remove a boost::shared_ptr from a list?从列表中删除 boost::shared_ptr 的正确方法是什么?
【发布时间】:2010-04-08 00:59:34
【问题描述】:

我有一个 std::listboost::shared_ptr<T>,我想从中删除一个项目,但我只有一个 T* 类型的指针,它与列表中的一个项目匹配。

但是我不能使用 myList.remove( tPtr ) 我猜是因为 shared_ptr 没有为它的模板参数类型实现 ==

我的直接想法是尝试myList.remove( shared_ptr<T>(tPtr) ),这在语法上是正确的,但由于临时的shared_ptr 有一个单独的use_count,它会因双重删除而崩溃。

std::list< boost::shared_ptr<T> > myList;

T* tThisPtr = new T(); // This is wrong; only done for example code.
                       // stand-in for actual code in T using 
                       // T's actual "this" pointer from within T
{
   boost::shared_ptr<T> toAdd( tThisPtr ); // typically would be new T()
   myList.push_back( toAdd );
}

{
   //T has pointer to myList so that upon a certain action, 
   // it will remove itself romt the list

   //myList.remove( tThisPtr);                      //doesn't compile
   myList.remove( boost::shared_ptr<T>(tThisPtr) ); // compiles, but causes
                                                    // double delete
}  

我看到剩下的唯一选择是将 std::find 与自定义比较一起使用,或者循环遍历列表蛮力并自己找到它,但似乎应该有更好的方法。

我是否遗漏了一些明显的东西,或者这太不标准了,无法以干净/正常的方式删除?

【问题讨论】:

    标签: c++ stl boost smart-pointers


    【解决方案1】:

    你说得对,我们不能直接比较指针。但是确实存在remove_if,我们可以指定我们自己的谓词。解决办法:

    template <typename T>
    struct ptr_contains_predicate
    {
        ptr_contains_predicate(T* pPtr) :
        mPtr(pPtr)
        {}
    
        template <typename P>
        bool operator()(const p& pPtr) const
        {
            return pPtr.get() == mPtr;
        }
    
        T* mPtr;
    };
    
    template <typename T>
    ptr_contains_predicate<T> ptr_contains(T* pPtr)
    {
        return ptr_contains_predicate<T>(pPtr);
    }
    

    只需将上述谓词放在标题中的某个地方,您就可以在任何地方使用它。

    myList.remove_if(ptr_contains(tThisPtr));
    

    最好的解决方案是一开始就永远不要失去对shared_ptr的控制,所以我们可以直接使用remove,但无论如何以上都是无害的。

    【讨论】:

    • 该死的! (领先我一分钟...)+1
    • C++0X 中不需要仿函数:myList.remove_if([ptr] (shared_ptr p) { return p.get() == ptr; });
    【解决方案2】:

    std::list 的remove_if 成员就是您所需要的:

    定义谓词

    template <typename T> struct shared_equals_raw
    {
      shared_equals_raw(T* raw)
        :_raw(raw)
        {}
      bool operator()(const boost::shared_ptr<T>& ptr) const
        {
          return (ptr.get()==_raw);
        }
    private:
      T*const _raw;
    };
    

    那你就可以打电话了

    myList.remove_if(shared_equals_raw(tThisPtr));
    

    让列表清理具有 shared_ptrs 到 tThisPtr 的节点。

    (未经测试,因此可能需要修复一些语法问题)。

    Michael Burr 关于 enable_shared_from_this 的建议虽然不错;最好完全避免使用原始的 tThisPtr。

    【讨论】:

    • 对不起,我不是故意踩你的脚趾,我没有看到你已经有了解决方案。 +1 表示正确答案,-0 表示不正确的语法。 :)
    • +1 表示正确,但是……我的眼睛!无法处理奇怪的压痕图案! :)
    【解决方案3】:

    enable_shared_from_this 可以帮助您解决问题,但它需要您在列表中使用的类型派生自它:

    如果类型启用了该功能,您可以通过调用 shared_from_this() 从对象本身获取共享指针。

    【讨论】:

      【解决方案4】:

      你可以使用共享指针来移除它吗?

      std::list< boost::shared_ptr<T> > myList;
      
      boost::shared_ptr<T> tThisPtr = new T(); 
      
      {
          myList.push_back(tThisPtr);
      }
      
      {
          myList.remove(tThisPtr);                     
      }
      

      【讨论】:

        猜你喜欢
        • 2013-10-16
        • 1970-01-01
        • 1970-01-01
        • 2014-03-26
        • 1970-01-01
        • 1970-01-01
        • 2012-01-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多