I always had the wrong impression that if I create temporaries in a function that returns a tuple, and use std::forward_as_tuple
in the return statement, then there is no copy, just like automatic copy elision for non-tuple return types.
How then can we avoid a copy? For example, in the following code, func1
“copies” the values 1 and 2 into temp
as it is being constructed, and there is no additional copy upon returning. func2
on the other hand does the same construction, but additionally copies when a tuple is created in the return statement.
I tried to be witty about it, and declare the temporary to be returned a tuple and construct a My_struct
in place, like this: std::tuple<My_struct> temp {{1,2}}
. But the copy constructor is still called. Adding a move constructor won't help as far as I can see since the data members are simple types.
#include <iostream>
#include <tuple>
struct My_struct {
int x, y;
My_struct(int x, int y) :
x(x), y(y)
{
std::cout << "Constructor called\n";
}
My_struct(const My_struct &a) :
x(a.x), y(a.y)
{
std::cout << "Copy constructor called!\n";
}
};
My_struct func1()
{
My_struct temp {1,2};
return temp;
}
std::tuple<My_struct> func2()
{
My_struct temp {1,2};
return std::forward_as_tuple(temp);
}
int main()
{
std::cout << "# Calling func1\n";
auto result1 = func1();
std::cout << "# Calling func2\n";
auto result2 = func2();
}
result:
# Calling func1
Constructor called
# Calling func2
Constructor called
Copy constructor called!