【问题标题】:How to erase elements from boost::ptr_vector如何从 boost::ptr_vector 中删除元素
【发布时间】:2008-12-10 13:17:39
【问题描述】:

所以我试图通过使用 boost::ptr_vector 来摆脱我的 std::vector。现在我正在尝试从一个元素中删除一个元素,并将删除的元素也删除。对我来说最明显的事情是:

class A
{ int m; };

boost::ptr_vector<A> vec;
A* a = new A;
vec.push_back(a);
vec.erase(a);

但这甚至不能编译(完整的错误信息见下文)。我已经像在 std::vector 上一样尝试了擦除/删除习语,但 boost::ptr_vector 的所有算法都与 std::vector 中的算法略有不同。

所以我的问题:

  • 如何从 ptr_vector 中删除指针?
  • 我还需要手动 delete() 删除的那个元素吗?

编译器错误:

1>------ Build started: Project: ptr_vector_test, Configuration: Debug Win32 ------
1>Compiling...
1>ptr_vector_test.cpp
1>c:\users\rvanhout\svn\trunk\thirdparty\boost\range\const_iterator.hpp(37) : error C2825: 'C': must be a class or namespace when followed by '::'
1>        c:\users\rvanhout\svn\trunk\thirdparty\boost\mpl\eval_if.hpp(63) : see reference to class template instantiation 'boost::range_const_iterator<C>' being compiled
1>        with
1>        [
1>            C=A *
1>        ]
1>        c:\users\rvanhout\svn\trunk\thirdparty\boost\range\iterator.hpp(63) : see reference to class template instantiation 'boost::mpl::eval_if_c<C,F1,F2>' being compiled
1>        with
1>        [
1>            C=true,
1>            F1=boost::range_const_iterator<A *>,
1>            F2=boost::range_mutable_iterator<A *const >
1>        ]
1>        c:\users\rvanhout\svn\trunk\thirdparty\boost\ptr_container\detail\reversible_ptr_container.hpp(506) : see reference to class template instantiation 'boost::range_iterator<C>' being compiled
1>        with
1>        [
1>            C=A *const 
1>        ]
1>        c:\tmp\ptr_vector_test\ptr_vector_test.cpp(21) : see reference to function template instantiation 'boost::void_ptr_iterator<VoidIter,T> boost::ptr_container_detail::reversible_ptr_container<Config,CloneAllocator>::erase<A*>(const Range &)' being compiled
1>        with
1>        [
1>            VoidIter=std::_Vector_iterator<void *,std::allocator<void *>>,
1>            T=A,
1>            Config=boost::ptr_container_detail::sequence_config<A,std::vector<void *,std::allocator<void *>>>,
1>            CloneAllocator=boost::heap_clone_allocator,
1>            Range=A *
1>        ]
1>c:\users\rvanhout\svn\trunk\thirdparty\boost\range\const_iterator.hpp(37) : error C2039: 'const_iterator' : is not a member of '`global namespace''
1>c:\users\rvanhout\svn\trunk\thirdparty\boost\range\const_iterator.hpp(37) : error C2146: syntax error : missing ';' before identifier 'type'
1>c:\users\rvanhout\svn\trunk\thirdparty\boost\range\const_iterator.hpp(37) : error C2208: 'boost::type' : no members defined using this type
1>c:\users\rvanhout\svn\trunk\thirdparty\boost\range\const_iterator.hpp(37) : fatal error C1903: unable to recover from previous error(s); stopping compilation
1>Build log was saved at "file://c:\tmp\ptr_vector_test\Debug\BuildLog.htm"
1>ptr_vector_test - 5 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

【问题讨论】:

    标签: c++ boost ptr-vector


    【解决方案1】:

    你也可以使用 std::vector 来做到这一点。

    在这两种情况下,erase 都将迭代器作为参数。
    因此,在您从向量(或 ptr_vector)中删除某些内容之前,您需要找到它。

    还请注意,ptr_vector 将其内容视为您存储了一个对象而不是指针。所以任何搜索都是通过对象完成的。

    基本上

     std::vector<A>       x;
     std::ptr_vector<A>   y;
    
     // These two object should behave in exactly the same way.
     // The ONLY difference is inserting values which for y are pointers.
     // Y take ownership of the pointer and all subsequent acesses to the
     // members of y look like they are objects
    

    例子:

    #include <boost/ptr_container/ptr_vector.hpp>
    #include <vector>
    
    class A
    { int m;
        public:
        A(int x):m(x)   {}
        bool operator==(A const& rhs)   {return m = rhs.m;}
    };
    
    int main()
    {
        boost::ptr_vector<A>    x;
        x.push_back(new A(1));
        x.erase(std::find(x.begin(),x.end(),A(1)));
    
    
        std::vector<A>          y;
        y.push_back(A(2));
        y.erase(std::find(y.begin(),y.end(),A(2)));
    
        // To find an exact pointer don't modify the equality.
        // Use find_if and pass a predicate that tests for a pointer
        A* a = new A(3);
        boost:ptr_Vector<A>     z;
        z.push_back(a);
        z.erase(std::find_if(y.begin(),y.end(),CheckPointerValue(a));
    }
    
    struct CheckPointerValue
    {
         CheckPointerValue(A* a):anA(a) {}
         bool operator()(A const& x)    { return &X == anA;}
         private:
            A* anA;
    };
    

    【讨论】:

    • 我认为您对我在下面的回答是正确的。如果我理解正确,默认分配器(heap_clone_allocator)在重新分配时会克隆对象本身)。不过,如果使用 view_clone_allocator 就可以了。我已经删除了我的答案并支持你。玩得开心:)
    • 谢谢,我的问题是我没有为 A* const & 定义 == 运算符,这似乎是必要的。为了让您的示例编译(VC9),我必须将“A const& rhs”更改为“A* const& rhs”并相应地更改正文的内容。这使得它很难与库类一起使用。
    • 你没有抓住重点! ptr_vector 像存储对象一样存储对象。与其破坏相等运算符,不如取消对指针的引用。如果你想找到一个精确的指针,你需要使用 find_if 并传递一个谓词。
    【解决方案2】:

    我认为您想在向量上调用 .release() 而不是擦除。这会删除条目并删除内存。

    详情请参阅the tutorial中的“新功能”部分,或查看the reference

    或者,您需要获取一个元素的迭代器才能调用 erase(),我不确定 A* 是否计入 ptr_vector。

    【讨论】:

    • 否 - release 从容器中移除指针,容器缩小,但对象没有被删除。它与auto_ptr release 具有相同的语义-您只需使用它来转移管理即可。
    【解决方案3】:

    你可以使用erase_if模板方法。

    vec.erase_if( predicate() );
    

    【讨论】:

    • 但是我需要编写一个专用谓词,它基本上是一个简单的比较函数对象?真是一团糟,如果这是我应该使用 ptr_vector 的方式,我将坚持使用 shared_ptr 的向量:/
    • 使用 boost::lambda 将谓词写成 lambda 函数(就地)。
    【解决方案4】:

    ptr_vector 的语义与常规的vector 非常相似。您必须先找到一个元素,然后才能擦除它。

    【讨论】:

    【解决方案5】:

    奇怪的是:STL::vector<> 是一个Random Access Container,意思是它使用了Random Access Iterators

    所以 vec.erase(vec.begin()+N) 将删除索引 N 处的元素。

    请注意,这样做会破坏整个 iterator 模因,您不能再在向量和列表之间轻松切换...

    【讨论】:

      【解决方案6】:

      您需要使用带有合适谓词的成员 erase_if 方法。不需要删除指针,容器有所有权。

      struct delete_a {
          bool operator()(boost::ptr_vector<A>::value_type inA) {
             return inA == a;
          }
      }
      
      vec.erase_if(delete_a());
      

      (请注意,这只是为了简单起见而选择的一个示例,对于实际代码中的这种情况,我想人们会编写一个合适的 bind/equal_to 组合,或者使用 lambda)

      或者,如果您仍想使用该对象,也可以在正确的迭代器上调用 release。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-30
        • 1970-01-01
        • 1970-01-01
        • 2011-02-28
        相关资源
        最近更新 更多