2

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!
fheshwfq
  • 303
  • 3
  • 11
  • FWIW, If it wasn't for the forced side-effect in your copy-constructor, it's very likely that this would be optimised away: https://gcc.godbolt.org/z/4q8cfKrc3, even without forward_as_tuple. –  Jun 17 '21 at 03:37

0 Answers0