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
orunique_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 delete
ing 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
How to Switch Between Blas Libraries Without Recompiling Program
How to Write Log Base(2) in C/C++
Is a Moved-From Vector Always Empty
Weird Behavior of Right Shift Operator (1 >> 32)
How to Compile Qt 5 Under Windows or Linux, 32 or 64 Bit, Static or Dynamic on Visual Studio or G++
What Is Shared_Ptr's Aliasing Constructor For
Why Istream Object Can Be Used as a Bool Expression
Reading from Ifstream Won't Read Whitespace
What Is a Non-Trivial Constructor in C++
Emulate "Double" Using 2 "Float"S
Using Qsocketnotifier to Select on a Char Device
What Is the Easiest Way to Parse an Ini File in C++
Does Vector::Erase() on a Vector of Object Pointers Destroy the Object Itself
Is Adding to a "Char *" Pointer Ub, When It Doesn't Actually Point to a Char Array