Isak T.
Isak T.

Reputation: 345

When to delete elements added to std::vector?

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

Upvotes: 0

Views: 294

Answers (3)

juanchopanza
juanchopanza

Reputation: 227390

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

Upvotes: 10

CPJoshi
CPJoshi

Reputation: 487

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

Upvotes: 0

Stack Overflow is garbage
Stack Overflow is garbage

Reputation: 247919

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. :)

Upvotes: -1

Related Questions