Questions about Vector Retention Behavior

Lately, I got a little confused about the memory allocation of (de) std::vectors

Suppose I got a normal integer vector: std::vector<int> intv; When I push_back some int , it grows in time. And when I leave the scope (i.e.) of the Function, it is freed up without the need for additional calls.

Great. Take 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); } 

Good. When I call hurr() , the vector is created, the foo_t instance is foo_t , the instance is populated and foo_t into the vector. So when I leave the function, the vector is freed and the content (here is one foo_t ) is also freed?

The following 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, a vector and its contents live on a stack that receives (eventually) time-rewritten and the vector that I returned, and its contents will be useless. Or does it really return a copy of the vector with a copy of its contents (this requires an instance of Copy-Constructor, if it's 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 need to manually iterate over the vector, delete its contents, and then I can safely allow the vector to fall out of scope, right?

+5
source share
3 answers

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

Upon completion of hurv() , foov and foo 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 of std::vector<foo_t> of hurr() valid with 1 foo_t in it and it is valid. return foov; can call the copy constructor std::vector<foo_t> , and he has the right not to make this 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 need to manually iterate over the vector, delete its contents, and then I can safely allow the vector to fall out of scope when you no longer want to use the result of hurr() , (not in hurr() )

+3
source
 foov.push_back(foo); 

Actually, you created foo_v and you threw it back, which actually created a new foo_v and named the copy constructor with foov as a parameter. Use emplace_back if you want to avoid this.

 return foov; 

The compiler can optimize this by optimizing the return value. See this short program. I made a run on coliru as an example. See other great answers in this question .

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

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

Yes Yes. For the same reasons

 int* a = new int(); 

There will be no delete a; when a dies.

+3
source

So when I leave the function, the vector becomes freed, and the content (here is one foo_t ) is also freed?

Yes. And if foo_t had a nontrivial destructor, it would be called.

Or does it really return a copy of the vector with a copy of its contents (this requires an instance of Copy-Constructor, if its not a POD)?

Yes, in this case it returns a copy. Modern compilers are likely to call the copy constructor for std::vector , which in turn will call the copy constructor of the contained type for each element. C ++ 17 introduces guaranteed return value optimization (RVO), so the copy constructor of your vector will not be called. However, if you set the optimization level to high, the modern compiler can also use RVO.

Now I need to manually sort through the vector, delete its contents and then I can safely allow the vector to fall out of scope, right?

Yes you are right. Consider using smart pointers if you don't want iteration to be done manually.

+2
source

Source: https://habr.com/ru/post/1259086/


All Articles