Lets say you have something like this
#include <iostream>
#include <vector>
using namespace std;
vector<int> test()
{
vector <int> x(1000);
for (int i = 0; i < 1000; i++)
{
x[i] = 12345;
}
return x;
}
int main(int argc, const char * argv[])
{
vector<int> a = test();
return 0;
}
where within a function you create a vector and fill it with some elements (in this case I chose 12345 but they won't necessarily all be the same).
I have read that the elements of the vector are stored on the heap whereas the reference and header data are stored on the stack. In the above code, when x
is returned a copy-constructor must be called, and this takes O(n) time to copy all the elements into a new vector.
However, is it possible to take advantage of the fact that all the elements already exist on the heap in order to just return something like a pointer to those elements and later just create a vector that uses that pointer in order to point to those exact same elements — thus avoiding the need to make a copy all the elements of a vector?
The compiler does this for you, freeing you up to write nice , easy-to-read code, rather than mangling your code for the sake of optimization.
When you return a value for a function, the compiler is allowed to elide the return value object. The net effect is that the compiler can just create x
in the actual memory location of a
.
Even if it doesn't do this (e.g. it chooses not to for some reason, or you disable it by a compiler switch), then there is still the possibility of a move.
When a move happens, the vector will just transfer ownership of the pointer from x
to the return value, and then from the return value to a
. This leaves x
etc. as an empty vector, which is then correctly destroyed.
You could explore this by writing a test class (instead of vector<int>
) which prints something out for its default constructor, copy-constructor, and move-constructor, e.g.
#include <iostream>
struct A
{
A() { std::cout << "default\n"; }
A(A const &) { std::cout << "copy\n"; }
A(A &&) { std::cout << "move\n"; }
};
A func() { A a; return a; }
int main()
{
A b (func());
}
Output with g++:
default
Output with g++ -fno-elide-constructors:
default
move
move
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