Does Vector::Erase() on a Vector of Object Pointers Destroy the Object Itself

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

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

Deleting an element from a vector of object pointers allocated on the stack

If you want to delete pointer element, delete will call object destructor. No need to call
List[id]->~Ball() also no need to set pointer to NULL as you are going to erase the element anyway.

std::vector<Ball*> List;

void BallManager::DeleteBall(int id)
{
if (id < List.size()) // should check id is still in range
{
delete List[id];
List.erase(List.begin()+id);
}
}

Strongly recommand you use smart pointer as Chris mentioned, then you don't need to worry about deleting object pointer when you delete element from STL container, demo as below:

  std::vector<std::shared_ptr<Ball> > List;
void BallManager::DeleteBall(int id)
{
if (id < List.size()) // should check id is still in range
{
List.erase(List.begin()+id);
}
}

How to remove object from a vector if it was deleted

From your sample code, I assume your vector is defined somewhat like this:

std::vector<YourType*> entities;

Therefore, your vector does not contain YourType objects, but pointer to YourType. That is, the elements the vector manages are the pointers, not the pointed objects.

Thus when you do this delete entities[x + y * width]; you indeed delete the YourType instance, but the pointer still exists and it sill in your vector.

It might be easier to visualize if you decompose that statement to the equivalent 2 lines:

YourType * pointer = entities[x + y * width];
delete pointer;

To actually remove the pointer from the vector, you need to say so:

entities.erase(entities.begin() + x + y * width);

This would remove the pointer from the array (also shifting all things past that index). You still need to do the delete yourself as, again, the vector is only managing the pointer, not the YourType.


Note that unless you have a good reason, you should probably not store the pointer in the vector, but the object itsself. That would remove your confusion:

std::vector<YourType> entities;

// deleting a YourType:
entities.erase(entities.begin() + x + y * width);

No delete or new anymore, because the object is directly in the vector. So the vector manages it for you instead of just managing the pointer and letting you deal with the pointed object.


Update after question edit:

In your case, you do have a good reason, because you actually store a non-owning pointer. So it might make sense that entities and projectiles store pointers, so they actually point at the same objects.

So both vectors will manage their pointers, but you have to think of how the lifecycle of those two pointers (the one from entities and the one from projectiles) interact with the object itself.

Deleting the object will not get rid of the pointers, in neither of the arrays.

Memory Garbage on vector.erase of pointer

Standard containers, like std::vector, containing raw pointers DO NOT automatically delete the things that the pointers are pointing at, when removing the pointers from the containers. If you want that, store smart pointers instead, ie std::unique_ptr or std::shared_ptr.

Does myVector.erase(myPtr) delete the object pointed by myPtr?

Yes, you created a memory leak by that. std::vector and other containers will just remove the pointer, they won't free the memory the pointer points to.

It's not unusual to put a pointer into a standard library container. The problem, however, is that you have to keep track of deleting it when removing it from the container. A better, yet simple, way to do the above, is to use boost::shared_ptr:

{ 
boost::shared_ptr<foo> f(new foo);

std::vector< boost::shared_ptr<foo> > v;
v.push_back(f);
v.erase(v.begin());
} /* if the last copy of foo goes out of scope, the memory is automatically freed */

The next C++ standard (called C++1x and C++0x commonly) will include std::shared_ptr. There, you will also be able to use std::unique_ptr<T> which is faster, as it doesn't allow copying. Using std::unique_ptr with containers in c++0x is similar to the ptr_container library in boost.

Deleting objects from a vector of pointers

As a number of comments have pointed out, vector.erase only removes the elements from the vector. It does NOT try to delete any associated memory.

To delete the associated memory explicitly, you need to:

int main(int argc, const char * argv[])
{
...

auto it = objs.begin() + i;
delete *it;
objs.erase(it);

}

Actually, in your case:

int main(int argc, const char * argv[])
{
std::vector<Obj*> objs;

Obj* o = new Obj(10);
objs.push_back(o);

auto it = objs.begin();
delete *it;
objs.erase(it);

}

There are a number of other inconsistencies with your code and, better solutions for what you're trying to do, such as:

  • Using a vector<Obj>:

    int main(int argc, const char * argv[])
    {
    std::vector<Obj> objs;
    objs.emplace_back(10);

    auto it = objs.begin();
    objs.erase(it);
    }
  • If you need to dynamically allocate your objects, but for some reason do not want the vector to handle that, you can use shared_ptr or unique_ptr, who will take care of the deallocation for you:

    int main(int argc, const char * argv[])
    {
    std::vector<std::unique_ptr<Obj>> objs;

    objs.emplace_back(new Obj(10));

    auto it = objs.begin();
    objs.erase(it);
    }

If I call delete on a pointer to a vector std::vector Object* *, will the elements be deleted as well?

No, and here's why.

Consider these two cases:

int a, b, c;

auto stackvec = new vector<int*> { &a, &b, &c };
auto heapvec = new vector<int*> { new int, new int, new int };

delete stackvec;
delete heapvec;

If calling delete on the vector*s called delete on the pointers they hold, then you'd be in for a heap of trouble (pun intended) because you'd be deleteing automatic variables with the first delete which yields undefined behaviour (a bad thing).

You have to manually iterate the vector and delete the pointers yourself when you know they're dynamically allocated, or better, use std::unique_ptr and you never need to call delete on anything.

Also, you probably don't need a pointer to a vector in the first place, but I won't judge you since I don't know your situation.

As for std::array and std::vector, you need to know the size of your std::array at compile time and you can't resize it at runtime, but vector has neither of those restrictions.

Is an object pointer in a vector deleted if I call delete on the object?

"Does the call to delete affect the pointer in the vector?"

It doesn't affect the pointer. It affects the behavior invoked by using this pointer since the object it points to no longer exists. When you call delete, the object is deleted and whatever you try to do with that object using invalid (old, dangling) pointer, the behavior is undefined.

std::vector<SomeObject *> testvector;
SomeObject * testobject = new SomeObject()
testvector.push_back(testobject);

Constructs a vector of pointers, creates an instace of SomeObject and pushes an address of this object to your vector. Then when you call:

delete testobject;

There is no way how std::vector could know that the object has been deleted. Your vector still contains an old pointer, which has became invalid by the time the object was deleted. A possible solution could be using a vector of smart pointers such as shared_ptr, however at first you should consider whether you want to use a vector of pointers at first place. Maybe std::vector<SomeObject> would be more reasonable way to go.

deleting a vector of pointers vs. object in c++

Calling a destructor on a pointer value does nothing. (On the other hand, calling delete on a pointer value runs the destructor for the pointed-to object, and frees the memory.)

In the case of an array of pointers to objects, you must free the objects manually if that's what you want.

Remove and delete pointers that match a condition in a vector

std::unique_ptr does the deletion for free:

std::vector<std::unique_ptr<GameObject>> gameObjects;

// Remove objects from vector
gameObjects.erase(
std::remove_if(
gameObjects.begin(),
gameObjects.end(),
[](const auto& p) { return p->isDestroyed(); }
),
gameObjects.end()
);

I suggest to use it instead. It also avoids mistakes like forgetting to delete or double deleting.



Related Topics



Leave a reply



Submit