4

Why do I need to delete dynamically created items in vector, manually? Why wouldn't they get deleted or its destructor called when vector got deleted?

Normally something like this, but why needed ?

vector<int*> v;
for (vector<int*>::iterator it = v.begin(); it != v.end(); ++it) 
{ 
   delete *it; 
}
Cole Tobin
  • 9,206
  • 15
  • 49
  • 74
daisy
  • 22,498
  • 29
  • 129
  • 265
  • If you have a vector of pointers, it get rids of the pointers. Destructors are not called because pointers themselves don't have destructors. – SiimKallas Aug 05 '12 at 00:37
  • @Ynau He is asking why the data at the pointer has to be deleted. – Cole Tobin Aug 05 '12 at 00:37
  • 6
    How is vector supposed to know that your items are "dynamically created"? You store pointers in your vector. Pointers can point anywhere. They can point to dynamic objects. They can point to static objects. They all can point to the same local object. How do you propose the vector is supposed to recognize and handle all these situations? – AnT stands with Russia Aug 05 '12 at 00:51
  • [related answer](http://stackoverflow.com/a/4261074/252000) – fredoverflow Aug 05 '12 at 07:21

4 Answers4

12

Firstly, you store raw pointers in your vector. These pointers are just pointers. They can point anywhere. They can point to local objects, which cannot be deleted by delete. And even if they point to dynamically created objects, it doesn't necessarily mean that the user wants them to die with the vector. How is the vector supposed to know all this?

It is a matter of object ownership. Whoever owns the object is responsible for its proper and timely deletion. Ordinary raw pointers do not express ownership. That is why vector can't make any assumptions about whether the objects need to be deleted or not. If you want to tell the vector that it owns its dynamic objects, use corresponding smart pointers.

Secondly, note that your deletion technique is not necessarily safe in the general case. Some standard containers assume that the data you store in them is always valid. When you do delete on each vector element, the data in the vector becomes "invalidated" (pointers become indeterminate). This is OK with a vector. But doing something like this in a "smarter" container, like std::map or std::unordered_set for example, can and will lead to problems. Even if you destroy the container itself immediately afterwards, it is perfectly possible that the container's destruction algorithm might need to analyze (compare, hash etc.) the values of individual elements. And you just killed them all with your cycle.

Smart pointers naturally resolve this matter. But if you have to use a manual delete for raw pointers stored in a standard container, a better sequence of steps would be this

  1. Retrieve the value of the element at i and store it in pointer p
  2. Erase the element at i from the container
  3. Do delete p

In the end you end up with an empty container and deleted data. Again, your approach will work for simple sequences, like std::vector or std::list, but don't do this with ordered or hashed ones.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • Great answer, and great point about the danger of deleting elements prematurely in `std::map` et al. – j_random_hacker Aug 05 '12 at 01:05
  • I don't understand the problem with deleting elements in `std::map`. Deleting a pointer does not change its value, right? – rafak Aug 05 '12 at 10:08
  • @rafak: When you have an `std::map` that stores pointers, most of the time you'd use a comparison function that compares *pointed objects*, not the pointers themselves. But you already destroyed the pointed objects. So, if after that moment the map decides to do a comparison for some reason, it will fail. It really depends on implementation. `std::map` implementations I saw don't do this. But `hash_map` in GCC implementation does: it will crash in the destructor if you pre-delete the pointed objects like that. – AnT stands with Russia Aug 05 '12 at 16:27
  • @AndreyT: ok thanks for the precision. I thought you were referring to the unspecifiedness of comparing pointers pointing to objects not in the same array. – rafak Aug 06 '12 at 08:41
6

Because the language has no way of knowing whether you need them to remain alive when you're done. What if you inserted some pointers to stack objects or something like that? Boom.

This, however, can be remedied by using a smart pointer, which will implement an appropriate policy as to automatic destruction. unique_ptr and shared_ptr are the most common and useful.

Puppy
  • 144,682
  • 38
  • 256
  • 465
3

The destructor is not called because the pointer does not own the object to which it points.

In C++11, a std::unique_ptr<T> does indeed own the object to which it points. In this case, the destructor is called when the pointer is released, which is probably the behavior you want. (If you don't have a C++11 compiler but have a reasonably recent pre-C++11 compiler, unique_ptr is still available as part of TR1.)

thb
  • 13,796
  • 3
  • 40
  • 68
1

The implementation of vector was just made to delete its memory only. Pointers do not have deconstructors. And in C++, there is no garbage collection or logic to see that it is pointers and recursive delete it.

If you would like to attend the next ISO meeting and propose that, be my guest, but for me, I just put it in an inline function:

template<class T>
public static inline void deleteVectorPointer(std::vector<T*> v)
{
    for (vector<T*>::iterator i = v.begin(); i != v.end(); i++)
    {
        delete *i;
    }
}
Cole Tobin
  • 9,206
  • 15
  • 49
  • 74