igel
igel

Reputation: 557

Avoid double-move when returning a pair in C++

I'm trying to write a function that returns a pair of objects, one of which is harder to construct than the other. This code comes close to illustrating what I'm trying:

#include<iostream>
#include<tuple>

using namespace std;

struct A {
  int i;
  A(A&& a): i(a.i) { cout << "move-constructing A: "<<a.i<<"\n"; }
  A(int j): i(j) { cout << "int-constructing A: "<<j<<"\n"; }
};
using APair = pair<A,A>;

APair get_As() {
  A a(8);
  return {piecewise_construct, make_tuple(move(a)), make_tuple(10)};
}

int main()
{
  APair As = get_As();
  return 0;
}

But, when I run this, I see a double move of the A constructed with 8:

int-constructing A: 8
move-constructing A: 8
move-constructing A: 8
int-constructing A: 10

I recon that's because the A is moved into the std::tuple and then into the APair of main(). Clearly, a single move should be sufficient to construct the APair, but I cannot see how I would do that, since the piecewise constructor seems unavoidable, which means I also have to provide a tuple... My question is thus: how can this be done with a single move of A?

Upvotes: 1

Views: 292

Answers (1)

Jarod42
Jarod42

Reputation: 217428

You might use std::forward_as_tuple to avoid extra move constructor:

return {piecewise_construct, std::forward_as_tuple(move(a)), make_tuple(10)};

Demo

So you have std::tuple<A&&> instead of std::tuple<A> (which move construct).

Upvotes: 1

Related Questions