#include <vector>
typedef std::vector<char> vc;
typedef std::vector<vc> vvc;
vvc f() {
const int N = (1 << 15);
return vvc(N, vc(N)); // 1 GB
}
int main () {
vvc v;
v = f();
while(true); // Why 2GB allocated ?
return 0;
}
Compiled with both clang -O2 and g++ -O2. Same behavior.
Edit: There are multiple ways to fix this code pointed in some of the answers. But my point is to understand this code. Of course there is a temporary object, but it should disappear at the semicolon and 1GB of memory should be returned to the system. The question intends to ask why it does not happen.
Edit 2: The destructor of temporary object is indeed called before semicolon.
My guess is that you're looking at the operating system display of how much memory is allocated to the process, and that your compiler doesn't yet support C++11's move assignment.
Therefore what happens is probably the following:
So the result is that the operating system allocates 2GB to your process, of which 1GB is allocated to the vector, and 1GB is free for future allocation within your program (but not to allocations in another process).
You have assignment in your code that we preach against in vain for good reason ;-)
If you used initialization, that allows RVO optimization, and as others experimented it actually seem working too.
With assignment the function return an object, then it must be copied to target and only then nuke the temporary. While with data flow anal it could be possibly optimized, it's a case that hard to catch and considered rare to use. Thus you suffer the performance penalty on top of all the rest.
EDIT: to see that the temporary is indeed nuked at the proper point I suggest using debugger and single-step into functions. Alternatively look at assy listing. For the abstract machine the dtor call must happen before the next instruction.
However, optimized code uses the 'as if' rule more liberally. If the code has no way to tell the difference, it may postpone it a little, and you may just experience that effect.
C++11 note: in C++11 vector gained another op= that moves from the rvalue. That would cure this particular case, but it will take time till all compilers close the gap and especially all classes gain moving stuff. Pre-11 code looking for moving would use swap() in place of =.
I've just tested on win32, vc7.
Your code allocates 2Gb. If change to this:
int main () {
vvc v = f();
while(true);
It needs only 1Gb.
I suppose the reason - is a copy operation between vectors.
v = f()
- invokes constructor. Your case - default c'tor and copy (operator =
) into empty object. Coping needs 2 Gb.
Internal actions of f()
(creating vector and return) can use RVO, and there are no any coping and extra allocating.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With