Does vector::erase() on a vector of object pointers destroy the object itself?
Asked Answered
K

5

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.

Kissee answered 15/6, 2011 at 4:50 Comment(2)
related answerFbi
Related: #4061938Lafreniere
M
78

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;
}
Munguia answered 15/6, 2011 at 4:53 Comment(10)
so does that mean that if it's a vector of pointers, the destructor won't be called?Kissee
+1 for being complete, saying "but If the contained object is a pointer it doesnt take ownership of destroying it."Tricky
@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).Taunt
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.Kissee
oh and because your answer covered everything, I chose yours. Thanks!Kissee
Might want to consider using std::for_each and making it a template -- then it'd work for all container types and contained objects.Velutinous
@Billy ONeal: Thanks for suggesting the more generic approach! I added the same to answer.Munguia
@als: Why is your deletion functor returning a bool? template <typename T> struct Deleter : public std::unary_function<T*, void> { void operator()(T* toDelete) { delete toDelete; } }; should be sufficient.Velutinous
i tested out your generic code...#include "functional" was not required on g++ 4.5.2Meow
I found this helpful, because I wasn't sure what would happen to a vector of name-value pairs stored as vector<string ** >. Now I have more confidence in dealing with this seeming opacity of OOD in C++.Fougere
W
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();
}
Woolridge answered 21/9, 2012 at 17:51 Comment(0)
V
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.

Velutinous answered 15/6, 2011 at 4:52 Comment(4)
Yeah, I'm using a vector of pointers to objects. Sorry, I didn't clarify that.Kissee
@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)Velutinous
oh ok, so just to clarify, if I have: vector<Plane *> 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?Kissee
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.Cody
B
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.

Ballerina answered 15/6, 2011 at 4:52 Comment(0)
T
1

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

Taunt answered 15/6, 2011 at 4:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.