Benedikt Mokroß Benedikt Mokroß - 1 month ago 7
C++ Question

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?

Answer

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