Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Questions on memorybehavior of vectors

I got a bit confused lately about the memory (de)allocation of std::vectors

Lets assume I got normal vector of integer: std::vector<int> intv; When I push_back some int's it grows by time. And when I leave the scope (i.e.) of the function, it gets deallocated without the need of extra calls.

Great. Lets have another example:

struct foo_t{
    std::string bar:
    unsigned int derp;
}
void hurr(){
    std::vector<foo_t> foov;
    foo_t foo;
    foo.bar = "Sup?";
    foo.derp = 1337;
    foov.push_back(foo);
}

Okay. When I call hurr() the vector gets created, a foo_t instance gets created, the instance gets filled and pushed to the vector. So when I leave the function, the vector gets deallocated and the content (here one foo_t) gets deallocated, too?

Next example:

struct foo_t{
    std::string bar:
    unsigned int derp;
}
std::vector<foo_t> hurr(){
    std::vector<foo_t> foov;
    foo_t foo;
    foo.bar = "Sup?";
    foo.derp = 1337;
    foov.push_back(foo);
    return foov;
}

In my understanding, the vector and its contents live in the stack, which gets (eventually) overwritten by time and the vector I have returned and its contents will be useless. Or does it actually returns a copy of the vector with a copy of its contents (requires a Copy-Constructor for the content datatype if its not a POD)?

And something obvious:

struct foo_t{
    std::string bar:
    unsigned int derp;
}
std::vector<foo_t*> hurr(){
    std::vector<foo_t*> foov;
    foo_t foo = new foo_t;
    foo->bar = "Sup?";
    foo->derp = 1337;
    foov.push_back(foo);
    return foov;
}

Now I have to manually iterate over the vector, delete its contents and then I can safely let the vector fall out of scope, right?

like image 740
bam Avatar asked Nov 01 '16 09:11

bam


People also ask

How are vectors stored in memory?

Vectors are assigned memory in blocks of contiguous locations. When the memory allocated for the vector falls short of storing new elements, a new memory block is allocated to vector and all elements are copied from the old location to the new location.

Does vector cause memory leak?

std::vector does not cause memory leaks, careless programmers do. You should also include an example that actually exhibits the behavior you are experiencing, including calls to the CRT debug API. There's a good possibility that you're incorrectly interpreting the leaks based on when they are reported.

Is vector a dynamic memory?

Vector are implemented as dynamic arrays with list interface whereas arrays can be implemented as statically or dynamically with primitive data type interface. Size of arrays are fixed whereas the vectors are resizable i.e they can grow and shrink as vectors are allocated on heap memory.

Are vectors continuous in memory?

Yes, the elements of a std::vector are guaranteed to be contiguous.


2 Answers

This example:

struct foo_t{
    std::string bar;
    unsigned int derp;
};
void hurr(){
    std::vector<foo_t> foov;
    foo_t foo;
    foo.bar = "Sup?";
    foo.derp = 1337;
    foov.push_back(foo);
}

After hurv() finished, foov and foo are both freed.

std::vector<foo_t> hurr(){
    std::vector<foo_t> foov;
    foo_t foo;
    foo.bar = "Sup?";
    foo.derp = 1337;
    foov.push_back(foo);
    return foov;
}

the result std::vector<foo_t> of hurr() is valid with 1 foo_t in it and it's valid. The return foov; may call a copy contructor of std::vector<foo_t>, and it have its free to not make that copy, see copy elision

Anyway, from C++11, you can write this:

struct foo_t{
    std::string bar;
    unsigned int derp;
    // we will copy the string anyway, pass-by-value
    foo_t(std::string bar_, unsigned int d_)
        : bar(std::move(bar_)), derp(d_) {}
};
std::vector<foo_t> hurr(){
    std::vector<foo_t> foov;
    // This is better, in place construction, no temporary
    foov.emplace_back("Sup?", 1337);
    // This require a temporary
    foov.push_back(foo_t{"Sup?", 1337});
    return foov;
}

And, for the last example, yes, you have to manually itterate over the vector, delete its contents and then I can safely let the vector fall out of scope when you no longer want to use the result of hurr(), (not in hurr())

like image 96
Danh Avatar answered Sep 29 '22 07:09

Danh


foov.push_back(foo);

Actually, you constructed a foo_v and you pushed it back, which actually created a new foo_v and called the copy constructor with foov as a paremeter. Use emplace_back if you want to avoid this.

return foov;

The compiler may optimize this using return value optimization. See this short program I've made running on coliru as an example. Refer to the other excellent answers in this question.

std::vector<foo_t*> foov;
/* add elements to foov with new */

Now I have to manually itterate over the vector, delete its contents and then I can safely let the vector fall out of scope, right?

Yes, you do. For the same reasons

int* a = new int();

Will not delete a; when a dies.

like image 37
Asu Avatar answered Sep 29 '22 08:09

Asu