When to delete elements added to std::vector? - c++

I'm new to C++ and have a question regarding memory management.
In the header, I have this:
std::vector<Obstacle::Obstacle*> obstacles;
and in the .cpp I do this:
Circle *circle = new Circle(x, y, radius);
obstacles.push_back(circle);
where Circle is a subclass of Obstacle.
My question is when should I call delete on the elements which are in the vector? I have heard each new should be balanced by a delete. Do I need to in the destructor loop through the vector and call delete on each element? Isn't there a more elegant way?
Thanks

You have to call delete on the elements before you clear the vector, or before the vector goes out of scope iff the vector owns the objects pointed at. A more elegant solution is to have the vector hold smart pointers. The particular type of smart pointer should depend on the ownership policy.
For example, a vector owning the pointed-at objects should use C++11 std::unique_ptr:
std::vector<std::unique_ptr<Obstacle>> obstacles;
Of course, all of the above is under the assumption that you actually have strong reasons to use pointers. Often the best solution is the simplest ones: hold items by value:
std::vector<SomeType> things;
Note that this doesn't apply in your case, where you are storing pointers to objects derived from a base class, since storing values of base type would result in object slicing.
Edit: One simple way to ensure the elements are deleted when the vector goes out of scope is to write a scope guard class:
template <typename CONTAINER>
struct PtrContainerGuard
{
PtrContainerGuard(CONTAINER& container) : c_(container) {}
~PtrContainerGuard()
{
for (typename CONTAINER::iterator it = c_.begin(); it != c_.end(); ++it)
delete (*it);
}
private:
CONTAINER& c_;
}
then
std::vector<Obstacle*> obstacles;
PtrContainerGuard<std::vector::Obstacle*> p(obstacles);

Why not use shared_ptr? You don't have to create new objects and worry about deleting them if you use them.
typedef shared_ptr<Obstacle> ObstaclePtr;
int main()
{
std::vector<ObstaclePtr> obstacles;
//Create objets using shared_ptr and push them in vector
ObstaclePtr obstacle1(new Circle());
obstacles.push_back(obstacle1);
ObstaclePtr obstacle2(new Circle());
obstacles.push_back(obstacle2);
//When vector obstacles goes out of scope here, all circles inside are destructed!
}

Yes, there is a more elegant way. Throw away all your pointers.
std::vector<Obstacle::Obstacle> obstacles;
Circle circle(x, y, radius);
obstacls.push_back(circle);
Nothing was new'ed, nothing needs to be deleted, you save a memory allocation, and access to the objects stored in the vector becomes more efficient.
Also, your code will no longer make the eyes bleed of more experienced C++ developers.
All in all, I call that a win. :)

Related

Memory error while working with an Manager and an vector

I want to create a Manager that holds multiple objects and has to be used in order to actually create the objects.
The objects hold their information in a smart pointer.
this is how I implemented it:
struct Object
{
std::shared_ptr<int> number;
};
struct Manager
{
std::vector<Object> objects;
Object& createObject()
{
objects.emplace_back();
return objects.back();
}
};
int main()
{
Manager manager;
Object& object1 = manager.createObject();
object1.number = std::make_shared<int>(10);
for (Object& o : manager.objects)
{
std::cout << *o.number << std::endl;
}
}
If I execute this code I get my expected output: 10
but once I try to create multiple objects like this:
Manager manager;
Object& object1 = manager.createObject();
Object& object2 = manager.createObject();
object1.number = std::make_shared<int>(10);
object2.number = std::make_shared<int>(5);
for (Object& o : manager.objects)
{
std::cout << *o.number << std::endl;
}
I get an runtime error in the memory library at this function:
void _Decref()
{ // decrement use count
if (_MT_DECR(_Uses) == 0)
{ // destroy managed resource, decrement weak reference count
_Destroy();
_Decwref();
}
}
does anybody know why this is happening?
It is never a good idea to use vectors of class instances in conjunction with pointers or references to these class instances. Like Bo Persson already correctly answered, these pointers or references tend to become dangling due to the dynamic nature of a std::vector: when a std::vector grows, it often copies its items to a different memory position, leaving the already existing item references and pointers invalid (dangling).
You can easily avoid that by storing pointers to classes instead of the classes itself.
struct Manager
{
std::vector<std::unique_ptr<Object>> objects;
Object& createObject()
{
objects.emplace_back(std::make_unique<Object>());
return *objects.back().get();
}
};
Now std::vector may move the unique_ptr's around as it likes - the smart pointers content (raw pointers) and thus also the references never change (except if you willful change or delete them, of course)
Here's an illustration what happens when you use a vector of class instances.
The grey vertical stripes symbolize the memory - the real structure of memory and sizes are ignored here.
Step 1: You have a vector (symbolized by square brackets) holding a class instance as an item. The memory behind the vector is occupied (reality is a little different, but the image should suffice)
Step 2: You create a reference (or pointer) to your class instance. (green arrow)
Step 3: You add a second class instance to the vector. The vector has no room for its items, and thus have to move its content to another memory position. Your pointer/reference is broken! (red arrow)
And here's an illustration of the pointer solution:
Step 1: You have a vector again, but now it's a vector of smart pointers. It holds a smart pointer pointing (dark green arrow) to a class instance.
Step 2: You again create a reference (or pointer) to your class instance. (green arrow)
Step 3: You add a second pointer to a class instance to the vector. The vector has no room for its items, and thus has to move its content to another memory position. But this time only the smart pointers are moved, not the class instances itself! Class instance 1 stays at its place, smart pointer 1 still points to class instance 1, your reference stays intact, and everyone stays happy :)
Additionally: Apart from being a safe solution, using pointer vectors instead of instance vectors very often also has a performance benefit. unique_ptr are very small, nearly always much smaller than the objects they hold pointers to. And so, when std::vector has to copy its items to a different memory position, it has lot less work to do if these are only small smart pointers.
On top of that, there are some classes, which have expensive copy constructors (e.g. locking!). All of that can be avoided if the class instance is not copied at all.
When adding new elements to the vector, you risk that references to the old objects get invalidated.
See http://en.cppreference.com/w/cpp/container/vector/emplace_back where it says:
If the new size() is greater than capacity() then all iterators and references (including the past-the-end iterator) are invalidated.
So after adding object2, the reference object1 might be invalid.

How to delete a pointer inside a struct object when the struct object goes out of scope?

I have a struct object that contains a pointer to an object.
struct Track
{
KalmanFilter* kalmanFilter; //Kalman filter for this track
....
};
I instantiate the struct and pointer objects by
Track track;
track.kalmanFilter = new KalmanFilter(contours[contour].centroid);
....
I then check each frame if the track is still valid by
//Temporary vector to hold alive tracks
std::vector<Track> tempTracks;
for(...)
{
//If track is valid save into temp tracks
if(tracks[track].deadTime <= deadTime) tempTracks.push_back(tracks[track]);
}
//Save all temp tracks back into tracks - this removes dead tracks that were in tracks
tracks = tempTracks;
After a while the micro-controller i'm using runs out of memory, this is the only pointer in my code so i'm pretty sure the KalmanFilter pointer is not being deleted.
So far I have tried a destructor in the Track struct which causes my micro-controller to hard fault immediately.
//Destructor frees up Kalman filter memory when the Track object goes out of scope
~Track()
{
if(kalmanFilter) delete kalmanFilter;
}
and I have tried using a unique_ptr but I cannot get the code to compile, all the examples I have found instantiate the object being pointed to at the same time as instantiating the unique_ptr. In my case I don't think I can do this.
What is the correct way to handle a situation like this?
Thanks
EDIT
So based on the comments there seems to be two main points.
Allocate the memory in the constructor
I have rewritten my struct to be
struct Track
{
Track(const Point& initialPosition) : kalmanFilter(initialPosition) {}
~Track() {}
KalmanFilter kalmanFilter; //Kalman filter for this track
};
and I instantiate it by
Track track(contours[contour].centroid);
Is this correct?
Find a better way to delete the tracks
What is the best way to remove an object from a vector without messing up the indexing during the loop? Using an STL iterator?
I implemented the solution from #M.M that seems to work
tracks.erase(std::remove_if(tracks.begin(), tracks.end(), [&](Track const &t){return t.deadTime > deadTime;}));
You can use a smart pointer:
struct Track
{
std::unique_ptr<KalmanFilter> kalmanFilter;
....
};
This means that when the Track is destroyed, if the smart pointer is managing a pointer it will invoke delete on that pointer.
It could be assigned by:
track.kalmanFilter.reset(new KalmanFilter(contours[contour].centroid));
although it'd be preferable to have this done by the constructor of Track.
This change will render Track non-copyable (but still movable). This is a good thing because previously your code did not behave properly on being copied anyway, so now the compiler will catch it for you.
You will need to modify your erase-loop to stop making copies of the elements. The normal way to do this is to use vector::erase combined with std::remove_if (the latter moves the selected elements to the end, and erase erases elements off the end):
tracks.erase( std::remove_if( begin(tracks), end(tracks),
[&](Track const &t) { return t.deadTime > deadTime; } ), end(tracks) );
Required includes would be <memory> and <algorithm>.
The way you are eliminating dead tracks will cause many copies of each track to be made.
The destructor to one of your many copies will try to deallocate that memory while active copies are still using that kalman filter which can cause issues. Also, if you can't guarantee it is NULL before being assigned... could be a random pointer being deleted.
In this situation I'd use a shared pointer. But to be honest, I feel like there is a better overall structure for how you are storing/using the tracks, I'd have to think about it and know more about the implementation though.
When you do push_back() you are creating a copy of the original Track object. Both the copy and the original object point to the same memory, and both at some point get destructed resulting in a double deallocation of the same address. Following the suggestions in the comments on better code organization will help avoid such bugs.

Copy from vector<pointer*> to vector<pointer*> in C++

I create a vector A and want to copy to a vector B in another class by using below method, is it a correct way? The vector A may be destroyed! I searched in google, but not found the good solution and meaningful explanation. Thanks everyone
void StateInit(vector<CButton*> listBtn)
{
_m_pListBtn = listBtn;
};
Yes and no, you are passing the vector by value:
void StateInit(vector<CButton*> listBtn)
{
_m_pListBtn = listBtn;
};
Wich means that listBtn is a copy of vector A (asuming we are calling vector A the one passed as parameter of StateInit), if you delete vector A, vector B will still have the collection of pointers and they will be valid since the destruction of a vector of pointers doesnt delete the pointed objects because it cant possible now how (should it call, delete, delete[], free?).
Do keep in mind that if you modify/delete one of the elements from vector A (using the pointers on the vector), that element will be modified in vector B (since its a pointer to the same element).
Im not sure what is your intend with this, but if you want to copy the whole vector, you should implement a clone mechanism for the objects and then copy them using transform:
class cloneFunctor {
public:
T* operator() (T* a) {
return a->clone();
}
}
Then just:
void StateInit(vector<CButton*> listBtn)
{
transform(listBtn.begin(), listBtn.end(), back_inserter(_m_pListBtn), cloneFunctor());
};
IF your intention is not to clone it but to share the pointers you should pass the vector as pointer or reference:
void StateInit(const vector<CButton*>& listBtn)
{
_m_pListBtn = listBtn;
};
A better way is to iterate on the new vector and push_back the elements to your vector.
See example code: std::vector::begin

C++ - Proper way of using std::vector & related memory management

Hy, I would like to ask a question that puzzles me.
I've a class like this:
class A {
private:
std::vector<Object*>* my_array_;
...
public
std::vector<Object*>& my_array(); // getter
void my_array(const std::vector<Object*>& other_array); // setter
};
I wanted to ask you, based on your experience, what is the correct way of implementing the setter and getter in a (possible) SAFE manner.
The first solution came to my mind is the following.
First, when I do implement the setter, I should:
A) check the input is not a referring to the data structure I already hold;
B) release the memory of ALL objects pointed by my_array_
C) copy each object pointed by other_array and add its copy to my_array_
D) finally end the function.
The getter may produce a copy of the inner array, just in case.
The questions are many:
- is this strategy overkilling?
- does it really avoid problems?
- somebody really uses it or are there better approaches?
I've tried to look for the answer to this question, but found nothing so particularly focused on this problem.
That of using smart pointers is a very good answer, i thank you both.. it seems I can not give "useful answer" to more than one so I apologize in advance. :-)
From your answers however a new doubt has raised.
When i use a vector containing unique_ptr to objects, I will have to define a deep copy constructor. Is there a better way than using an iterator to copy each element in the vector of objects, given that now we are using smart pointers?
I'd normally recommend not using a pointer to a vector as a member, but from your question it seems like it's shared between multiple instances.
That said, I'd go with:
class A {
private:
std::shared_ptr<std::vector<std::unique_ptr<Object> > > my_array_;
public
std::shared_ptr<std::vector<std::unique_ptr<Object> > > my_array(); // getter
void my_array(std::shared_ptr<std::vector<std::unique_ptr<Object> > > other_array); // setter
};
No checks necessary, no memory management issues.
If the inner Objects are also shared, use a std::shared_ptr instead of the std::unique_ptr.
I think you are overcomplicating things having a pointer to std::vector as data member; remember that C++ is not Java (C++ is more "value" based than "reference" based).
Unless there is a strong reason to use a pointer to a std::vector as data member, I'd just use a simple std::vector stored "by value".
Now, regarding the Object* pointers in the vector, you should ask yourself: are those observing pointers or are those owning pointers?
If the vector just observes the Objects (and they are owned by someone else, like an object pool allocator or something), you can use raw pointers (i.e. simple Object*).
But if the vector has some ownership semantics on the Objects, you should use shared_ptr or unique_ptr smart pointers. If the vector is the only owner of Object instances, use unique_ptr; else, use shared_ptr (which uses a reference counting mechanism to manage object lifetimes).
class A
{
public:
// A vector which owns the pointed Objects
typedef std::vector<std::shared_ptr<Object>> ObjectArray;
// Getter
const ObjectArray& MyArray() const
{
return m_myArray
}
// Setter
// (new C++11 move semantics pattern: pass by value and move from the value)
void MyArray(ObjectArray otherArray)
{
m_myArray = std::move(otherArray);
}
private:
ObjectArray m_myArray;
};

issues related to the copy of vector with pointer item

I want to ask whether there are some problems with the copy for the vector of pointer items. Do I need to strcpy or memcpy because there may be depth copy problem?
For instance:
Class B;
Class A
{
....
private:
std::vector<B*> bvec;
public:
void setB(std::vector<B*>& value)
{
this->bvec = value;
}
};
void main()
{
....
std::vector<const B*> value; // and already has values
A a;
a.setB(value);
}
This example only assign the value to the class variable bvec inside A class. Do I need to use memcpy since I found that std::vector bvec; has pointer items? I am confused with the depth copy in C++, could you make me clear about that? Thank you.
Think about this, if you remove and delete an item from the vector value after you call setB, then the vector in A will have a pointer that is no longer valid.
So either you need to do a "deep copy", have guarantees that the above scenario will never happen, or use shared smart pointers like std::shared_ptr instead of raw pointers. If you need pointers, I would recommend the last.
There is another alternative, and that is to store the vector in A as a reference to the real vector. However, this has other problems, like the real vector needs to be valid through the lifetime of the object. But here too you can use smart pointers, and allocate the vector dynamically.
It is unlikely you need strcpy or memcpy to solve your problem. However, I'm not sure what your problem is.
I will try to explain copying as it relates to std::vector.
When you assign bvev to value in setB you are making a deep copy. This means all of the elements in the vector are copied from value to bvec. If you have a vector of objects, each object is copied. If you have a vector of pointers, each pointer is copied.
Another option is to simply copy the pointer to the vector if you wish to reference the elements later on. Just be careful to manage the lifetimes properly!
I hope that helps!
You probably want to define your copy constructor for class A to ensure the problem your asking about is handled correctly (though not by using memcpy or strcpy). Always follow the rule of three here. I'm pretty sure with std::vector your good, but if not, then use a for loop instead of memcpy