53

I have a vector of pointers to objects. I need to remove an element from the vector and place that element in another list.

I read that erase can be used to remove the object from the vector, but I also read that it calls the objects destructor before doing so.

I need to know whether or not erasing the object will destroy it as well.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
cesar
  • 8,944
  • 12
  • 46
  • 59
  • [related answer](http://stackoverflow.com/questions/4260464/does-stdlistremove-method-call-destructor-of-each-removed-element/4261074#4261074) – fredoverflow Jul 05 '11 at 06:59
  • Related: http://stackoverflow.com/questions/4061438/what-do-i-need-to-do-before-i-delete-elements-in-a-vector-of-pointers-to-dynamic – bwDraco Sep 21 '12 at 17:27

5 Answers5

77

vector::erase
Removes from the vector container and calls its destructor but If the contained object is a pointer it doesnt take ownership of destroying it.

You will have to explicitly call delete on each contained pointer to delete the content it is pointing to, for example:

void clearVectorContents( std::vector <YourClass*> & a ) 
{    
    for ( int i = 0; i < a.size(); i++ ) 
    {       
        delete a[i];    
    }    
    a.clear(); 
} 

Storing raw pointers in standard containers is not a good idea. If you really need to store resources that have to be allocated by new, then you should use boost::shared_ptr. Check out the Boost documentation.

An more generic & elegant solution:
This solution makes use of for_each & templates as @Billy pointed out in comments:

// Functor for deleting pointers in vector.
template<class T> class DeleteVector
{
    public:
    // Overloaded () operator.
    // This will be called by for_each() function.
    bool operator()(T x) const
    {
        // Delete pointer.
        delete x;
        return true;
    }
};

And this can be called as:

for_each( myclassVector.begin(),myclassVector.end(),
          DeleteVector<myclass*>());

where, myclassVector is your vector containing pointers to myclass class objects.

Usage Example:

#include "functional"
#include "vector"
#include "algorithm"
#include "iostream"

//Your class
class myclass
{
    public:
        int i;
        myclass():i(10){}
};


// Functor for deleting pointers in vector.
template<class T> class DeleteVector
{
    public:
    // Overloaded () operator.
    // This will be called by for_each() function.
    bool operator()(T x) const
    {
        // Delete pointer.
        delete x;
        return true;
    }
};


int main()
{
    // Add 10 objects to the vector.
    std::vector<myclass*> myclassVector;

    for( int Index = 0; Index < 10; ++Index )
    {
        myclassVector.push_back( new myclass);
    }

    for (int i=0; i<myclassVector.size(); i++) 
    {
        std::cout << " " << (myclassVector[i])->i;
    }

    // Now delete the vector contents in a single  line.
    for_each( myclassVector.begin(),
              myclassVector.end(),
              DeleteVector<myclass*>());

    //Clear the vector 
    myclassVector.clear();

    std::cout<<"\n"<<myclassVector.size();

    return 0;
}
Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • 2
    so does that mean that if it's a vector of pointers, the destructor won't be called? – cesar Jun 15 '11 at 04:54
  • 7
    +1 for being complete, saying `"but If the contained object is a pointer it doesnt take ownership of destroying it."` – Nawaz Jun 15 '11 at 05:11
  • 2
    @anonymous That's right. The pointer itself will get destroyed, but it's up to the programmer to explicitly free the memory to which it refers (assuming the memory isn't used elsewhere). – Dominic Gurto Jun 15 '11 at 05:36
  • Thanks for the tip on boost. It may be helpful in the future. I'm currently using a game engine, cocos2d-x, and it supposedly performs garbage collection automatically. – cesar Jun 15 '11 at 05:52
  • oh and because your answer covered everything, I chose yours. Thanks! – cesar Jun 15 '11 at 05:52
  • Might want to consider using `std::for_each` and making it a template -- then it'd work for all container types and contained objects. – Billy ONeal Jun 15 '11 at 16:23
  • @Billy ONeal: Thanks for suggesting the more generic approach! I added the same to answer. – Alok Save Jun 16 '11 at 04:26
  • @als: Why is your deletion functor returning a bool? `template struct Deleter : public std::unary_function { void operator()(T* toDelete) { delete toDelete; } };` should be sufficient. – Billy ONeal Jun 16 '11 at 17:38
  • i tested out your generic code...#include "functional" was not required on g++ 4.5.2 – ashishsony Jul 03 '11 at 07:08
  • I found this helpful, because I wasn't sure what would happen to a vector of name-value pairs stored as vector. Now I have more confidence in dealing with this seeming opacity of OOD in C++. – Jerry Miller Aug 22 '14 at 13:21
14
  • If you have a vector<MyObject> then MyObject::~MyObject will be called.
  • If you have a vector<MyObject*> then delete <MyObject instance> will not be called.

To move MyObject between two vectors, you need to first insert it into the destination vector, then erase the original. Note that this will create a new copy of the object. When moving pointers, you can just keep the pointer in a temporary variable, erase it from the vector, then insert wherever you need.

And here's another simple way to delete and then remove all the items in a vector:

template<class T> void purge( std::vector<T> & v ) {
    for ( auto item : v ) delete item;
    v.clear();
}
Tomas Andrle
  • 13,132
  • 15
  • 75
  • 92
2

Yes, erase destroys the element. However, if you're placing the element in another container you probably made a copy putting it into that other container. The only way you'd run into issues is if you copied a pointer or something like that into the other container.

Billy ONeal
  • 104,103
  • 58
  • 317
  • 552
  • Yeah, I'm using a vector of pointers to objects. Sorry, I didn't clarify that. – cesar Jun 15 '11 at 04:53
  • @anonymous: Ah, well the "destructor" of the pointer would be called then. Which of course, does nothing. The vector destroys what it actually contains, not anything referenced from there. (Note that means you have to go back and `delete` those manually) – Billy ONeal Jun 15 '11 at 04:54
  • oh ok, so just to clarify, if I have: `vector p, q;` `Plane *r = new Plane();` `p.push_back(r);` `q.push_back(r);` `p.erase(p.begin());` r and q.begin() would still reference the newly created Plane? – cesar Jun 15 '11 at 04:59
  • 3
    It's the same behaviour as if you just wrote `{ Plane * p = new Plane; }`, when `p` goes out of scope it is "destroyed" but the allocated object still lives on the heap. Using naked pointers makes them *your* responsibility. – Kerrek SB Jun 15 '11 at 06:29
1

Yes, of course it will. If the object doesn't exist in the vector, where else would it exist?

Edit: This will not delete anything pointed to by a pointer. You should use automatic life-time managing pointers such as shared_ptr to manage object lifetimes.

Puppy
  • 144,682
  • 38
  • 256
  • 465
1

Yes. vector::erase destroys the removed object, which involves calling its destructor.

Dominic Gurto
  • 4,025
  • 2
  • 18
  • 16