11

As far as I know that for both vector declarations as:

//TYPE 1
std::vector<cls> vec;     //cls is user defined datatype(A class)

Memory for vector is allocated on stack and the memory of contents in the vector is allocated on heap.

It is true for the below declaration as well(Correct me if I am wrong):

//TYPE 2
std::vector<cls*> vec;    //cls is user defined datatype(A class)

Now when the vector in Type 1 goes out of scope, memory is deallocated for the objects stored in it.

But what happens in type 2 if I insert elements as below(assuming that I have the proper overloaded constructor) and then the vector goes out of scope:

vec.push_back(new cls(5));

I explicitly tried calling clear but the destructor was not invoked. Will the memory be automatically be deallocated and the destructors be called. If not then how to achieve that.

Also, where is memory allocated for the vector as well as the contents if I declare vector as:

std::vector<cls*> *vec = new std::vector<cls*>;
Ziv
  • 2,325
  • 3
  • 21
  • 37
Saksham
  • 8,110
  • 6
  • 35
  • 63
  • "Will the memory be automatically be deallocated and the destructors be called?" - No. Only the memory for storing the pointers. "how to achieve that?" - Release it explicitly, use a smart pointer or just use the first form. It's a container, let it contain the objects. – StoryTeller - Unslander Monica Jul 29 '13 at 13:46
  • 1
    In C++ generally we don't use the term stack but automatic storage for more info see: http://stackoverflow.com/questions/6500313/why-should-new-be-used-as-little-as-possible/6500497#6500497 – hetepeperfan Jul 29 '13 at 13:52
  • As a general rule: Don't use raw pointers in std collections. They will not be automatically cleaned up, so you can quite easy have a memory leak on your hands. Use shared_ptr instead, which is available in boost. – martiert Jul 29 '13 at 14:00
  • possible duplicate of [stl vector memory management](http://stackoverflow.com/questions/1009137/stl-vector-memory-management) – Ziv Jan 07 '14 at 10:48

8 Answers8

5

This is why we have smart pointers.

{
    std::vector<std::unique_ptr<cls>> vec;

    // C++14 will allow std::make_unique
    vec.emplace_back(std::unique_ptr<cls>(new cls(5)));
}

When the vector goes out of scope, the destructors of the unique_ptrs will be called and the memory will be deallocated.

In your case, with the raw pointers, you'd have to delete whatever you created with new manually:

// Something along the lines of this.
for (auto&& elem : vec) {
    delete elem;
}

Also, where is memory allocated for the vector as well as the contents if I declare vector as:

You're allocating the vector with new, so it'll be on the heap.

user123
  • 8,613
  • 2
  • 25
  • 50
  • can you please include snippet to explicitly delete the objects? – Saksham Jul 29 '13 at 13:52
  • @Saksham **DON'T** explicitly delete objects. – Bartek Banachewicz Jul 29 '13 at 13:53
  • @Saksham I have provided an example, but you may want to stick to allowing RAII to manage your memory for you. It's much nicer to just use the vectors of smart pointers because in the case of an exception, they would go out of scope and you wouldn't have memory leaks ^^. With raw pointers, you have more of a load on your back to manage – user123 Jul 29 '13 at 13:55
  • @BartekBanachewicz Okay. I will take care not to delete that way. I was just clearing my concepts. Thanks! – Saksham Jul 29 '13 at 13:55
4

But what happens in type 2 if I insert elements as below(assuming that I have the proper overloaded constructor) and then the vector goes out of scope:

The memory will leak - you'll need to iterate your vector and delete each element individually.

Bukes
  • 3,558
  • 1
  • 14
  • 20
  • can you please include snippet to explicitly delete the objects? – Saksham Jul 29 '13 at 13:48
  • 1
    for (vector::iterator it = vec.begin(); it != vec.end(); ++it) delete *it; – Neil Kirk Jul 29 '13 at 13:51
  • 2
    Saksham, you will write much better code if you take the time to learn smart poitners which do not require you to explicitly delete the objects. – Neil Kirk Jul 29 '13 at 13:53
  • I was trying it by accessing the vector elements through index as delete *vec[0]. Is it not possible? – Saksham Jul 29 '13 at 13:53
  • Yes but you don't need the * as it already returns the pointer and you can only call delete on pointers, not the dereferenced object. – Neil Kirk Jul 29 '13 at 14:02
3

If you store a pointer to an object in a vector, you will need to delete the elements before destroying the vector (or have a memory leak, but that's not a good thing). But you shouldn't use "raw" pointers. If you use for example unique_ptr<cls> instead of *cls, the problem is solved.

So instead of:

vec.push_back(new cls(5))

use

vec.push_back(unique_ptr(new cls(5)))

or

vec.push_back(make_unique<cls>(5))

and you won't have to worry about finding some place to iterate over the vector and delete the content.

There is very few situations where a new vector<...> is "right". If you do this, think about whether it is really necessary.

Mats Petersson
  • 119,687
  • 13
  • 121
  • 204
2

Nope for this type you can push back a new cls byt doing vec.push_back (new cls)

//TYPE 2
vector<cls*> vec;    //cls is user defined datatype(A class)

however the vector will clean the memory of the pointer variables, but not to the instances they point to, you have to run delete on every cls* inside vec. Otherwise you have a memory leak.

hetepeperfan
  • 3,787
  • 1
  • 23
  • 42
2

A std::vector will not delete the objects stored in it if they are dynamically allocated. You will have to do so yourself. It is best to avoid using raw memory at all -- usually you want to wrap your pointers in std::shared_ptr or std::unique_ptr instead. They will both automatically free the memory for you.

Don't create vector by using new.

Lstor
  • 2,235
  • 16
  • 25
2

The memory for vector is not necessarily allocated on stack. As you show in your last snippet, the memory for vector can be allocated from the heap.

When a vector goes out of scope from the stack, or when the vector is destroyed with delete if it were allocated with new on the heap, it will automatically destroy all its elements. However, regular pointers have no destructor and do not do anything special with the object they point to when they die. So although clearing a vector of pointers, destroys the pointers, the objects they point to are NOT destroyed.

There are two solutions. Before clearing the vector, iterate through every pointer in the vector and call delete on it. A better solutin is to use a smart pointer, such a unique_ptr. When a unique_ptr is destroyed, the object it points to is automatically deleted.

So with a

vector<unique_ptr<cls>>

, you can push back new cls as you have done so, and when the vector is destroyed, all the cls objects you inserted into the vector via the unique_ptr are also destroyed.

Neil Kirk
  • 20,002
  • 5
  • 48
  • 79
2

A vector holding pointers isn't responsible for the memory the pointers point to. When the vector goes out of scope, it will free the memory it had for the pointers, not the memory pointed to by these pointers.

It's still your responsibility to manage this memory. That's why you should use smart pointers as std::unique_ptr, or std::shared_ptr to avoid memory leaks (that may happen if you forgot to delete manually).

Also, where is memory allocated for the vector as well as the contents if I declare vector as:

vector<cls*> *vec = new vector<cls*>;

The vector is on the heap, the content is wherever it was (for example, it may be on the heap if you allocated it by new, or on the stack if you did : cls myCls; cls* myPointerToCls = &cls;, and then vec.push_back(myPointerToCls);)

JBL
  • 11,860
  • 4
  • 46
  • 76
1

Okay lots of nice answers,

You'll need to iterate your vector and delete each element individually

I'll show a small example :

class cls
{

public:
  cls(int x) :_a(x) {}
  ~cls() {cout<<"I'm Destroyed"<<endl ;}
 private:
 int _a;

};

int main()
{
vector<cls*> vec ;

for(auto i=1;i<=10;i++)
    vec.push_back(new cls(i));

for (auto it = vec.begin(); it != vec.end(); ++it) 
    delete *it;

{
vector<cls*> vec2 ;

vec2.push_back(new cls(10));
}
   //Here  vec2 out of scope
}

Output: I'm Destroyed < Only 10 times>

P0W
  • 42,046
  • 8
  • 62
  • 107
  • I was trying it by accessing the vector elements through index as delete *vec[0]. Is it not possible? – Saksham Jul 29 '13 at 14:01
  • @Saksham Referring my example `delete vec2[0];` will work in that particular scope. You can see the message printed. – P0W Jul 29 '13 at 14:07