I have read Dave Abrahams article on RVO and a few other Q/As on SO (14043609, 9293726 and 10818278) but I still have a question. When I compile and run the following code, I get this output:
Address of v in func 0x7fffac6df620
Address of v.data in func 0x2081010
Address of v in main 0x7fffac6df690
Address of v.data in func 0x20811b0
9
To me it seems that a copy is made. How do I pass large objects out of functions? Please note that I want to return one or more objects without writing an explicit structure for it. I used GCC 4.6.3 with -O2. Edit: The first two answers showed me that I expected too much from the compiler. I added a main2 that behaves in the same way, e.g. the printed addresses are different. I would like to emphasize that the motivation is efficient return of large objects.
#include <iostream>
#include <vector>
#include <tuple>
std::tuple<std::vector<int>, double> func() {
std::vector<int> v;
v.reserve(100);
for (int k=0;k!=100;k+=1)
v.push_back(k);
double a = 5.0;
std::cout << "Address of v in func\t" << &v << std::endl;
std::cout << "Address of v.data in func\t" << v.data() << std::endl;
return make_tuple(v, a);
}
int main() {
std::vector<int> v;
double a;
std::tie(v, a) = func();
std::cout << "Address of v in main\t" << &v << std::endl;
std::cout << "Address of v.data in func\t" << v.data() << std::endl;
std::cout << v[9] << std::endl;
return 0;
}
int main2() {
auto tp = func();
std::vector<int> & v = std::get<0>(tp);
double & a = std::get<1>(tp);
std::cout << "Address of v in main\t" << &v << std::endl;
std::cout << "Address of v.data in func\t" << v.data() << std::endl;
std::cout << v[9] << std::endl;
return 0;
}
As already said, there are two things that prevent RVO. The function doesn't return v
, but instead a tuple that is constructed form v
and a
. Also in main function v
is assigned and not constructed from the return value.
To get what you want you could use the tuples directly without additional vector objects:
#include <iostream>
#include <vector>
#include <tuple>
std::tuple<std::vector<int>, double> func() {
std::tuple<std::vector<int>, double> t;
get<0>(t).reserve(100);
for (int k=0;k!=100;k+=1)
get<0>(t).push_back(k);
get<1>(t) = 5.0;
std::cout << "Address of v in func\t" << &get<0>(t) << std::endl;
std::cout << "Address of v.data in func\t" << get<0>(t).data() << std::endl;
return t;
}
int main()
{
std::tuple<std::vector<int>, double> t = func();
std::cout << "Address of v in main\t" << &get<0>(t) << std::endl;
std::cout << "Address of v.data in func\t" << get<0>(t).data() << std::endl;
std::cout << get<0>(t)[9] << std::endl;
return 0;
}
Output:
Address of v in func 0x28fe80
Address of v.data in func 0x962c08
Address of v in main 0x28fe80
Address of v.data in func 0x962c08
9
Alternative optimization is to use move semantics when constructing the tuple:
return make_tuple(std::move(v), a);
In this case at least copying the vector's internal buffer is avoided:
Address of v in func 0x28fdd4
Address of v.data in func 0xa72c08
Address of v in main 0x28fe64
Address of v.data in func 0xa72c08
9