Search code examples
c++boostptr-vector

How to erase elements from boost::ptr_vector


So I'm trying to get rid of my std::vector's by using boost::ptr_vector. Now I'm trying to remove an element from one, and have the removed element deleted as well. The most obvious thing to me was to do:

class A
{ int m; };

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

But this won't even compile (see below for the full error message). I've tried the erase/remove idiom like I would on a std::vector but all the algorithms of boost::ptr_vector turn out to be slightly different from those in std::vector.

So my questions:

  • How do I remove a pointer from a ptr_vector?
  • Do I still need to manually delete() that element that I removed?

Compiler error:

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 ==========

Solution

  • Well you can do that with a std::vector either.

    In both cases erase takes an iterator as a parameter.
    So before you can erase something from a vector (or a ptr_vector) you need to locate it.

    Also note that the ptr_vector treats its content as if you have stored an object not a pointer. So any searching is done via the object.

    So basically

     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
    

    Example:

    #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;
    };