3

Let's assume I have a class with only one constructor:

class T {
 public:
  T(BigClass&& big) : big(std::move(big)) {}
  ...

  SomeBigClass
};

In most places the constructor is called on temporaries but in one place I need to make an explicit copy of BigClass because it is not a temporary and will be used multiple times in a loop:

void foo(const BigClass& big) {
  while (...) {
    T t(std::make_a_copy(big));
    ...
  }
}

Is there any function "dual" to std::move in C++11 or C++14 that would replace make_a_copy above ?

Edit: Some clarifications.

Cassio Neri
  • 19,583
  • 7
  • 46
  • 68
Łukasz Lew
  • 48,526
  • 41
  • 139
  • 208
  • If you may need to make a copy then shouldn't you also supply a `T(BigClass const & big)` constructor and then invoke that instead? – cdhowie Jul 05 '13 at 22:52
  • 1
    Why do you need to make a copy of a *temporary*, instead of a move? That seems kinda non-sensical. – Xeo Jul 05 '13 at 23:26
  • Someone should probably reject my edit. – Pixelchemist Jul 05 '13 at 23:48
  • If you want to write as few functions as possible, the two "core" are the copy constuctor, and `swap`. Move constructor, copy assignment, and move assignment can be written in terms of copy constructor and swap. Without a copy constructor... no shortcuts. – Mooing Duck Jul 06 '13 at 00:07
  • This question is quite unrelated to what the title says. The dual of `std::move` would be needed in a situation where you've got an rvalue reference expression and you need a _modifiable_ lvalue reference (which won't bind if you write it like that, and creating a temporary from the rvalue won't work either, because it can only initialise `const` lvalue references). That is not the case here, you have the exact opposite situation; it could be made to compile with `std::move` but that does not do what you want. The solution is to copy the `big` value first, which is unrelated to your `class T`. – Marc van Leeuwen Jul 21 '14 at 08:44
  • In *this* example `foo(const BigClass&)` (const ref!) the move constrcutor *already* will *not* be invoked, as you cannot move out of a const object. – Martin Ba Nov 19 '14 at 20:53
  • Question has a [duplicate](http://stackoverflow.com/questions/17543093/does-the-inverse-of-stdmove-exist) that provides additional infos. – Martin Ba Nov 19 '14 at 20:59

3 Answers3

6

Why can't you just copy the BigClass object?

void foo(const BigClass& big) {
  while (...) {
    T t{ BigClass(big) };
    ...
  }
}

This makes a temporary BigClass that is then moved into the T

Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
  • 1
    That doesn't look like it even needs the explicit copy. – Xeo Jul 07 '13 at 01:02
  • 1
    @Xeo: Yes it does need the explicit copy; the question explicitly says the _unique_ constructor of `T` takes `BigClass&&`, in particular there is no constructor `T::T(const BigClass&)` whose use would create and bind the temporary for you. – Marc van Leeuwen Jul 21 '14 at 08:49
1

It's not hard to write:

template <typename T>
T make_temp(const T& x) { return x; }

There might be a standard function that happens to do that by accident when called with one argument, but there isn't one designed for this unusual pattern.

aschepler
  • 70,891
  • 9
  • 107
  • 161
-1

If you can manipulate T you could template the constructor.

#include <iostream>
using namespace std;
class B
{
  int x;
public:
  B (int i) : x(i) { }
  B (B && b) : x(b.x) { cout << "B moved (" << x << ")" << endl; }
  B (B const  & b) : x(b.x)  { cout << "B copied (" << x << ")" << endl; }
};


class A
{
  B b;
public:
  template<typename TB>
  A (TB && init_b) : b(std::forward<TB &&>(init_b)) { }
};

B foo (void) { B x(3); return x; }


int main (void)
{
  A a1(foo());
  B b1(4);
  A a2(b1);
  return 0;
}

Prints

B moved (3)
B copied (4)

As far as I understand reference collapsing you should come out with a constructor A(B&) forwarding to the copy constructor of B and a A(B&&) forwarding to the move constructor of B.

Pixelchemist
  • 24,090
  • 7
  • 47
  • 71
  • 2
    Your test is deeply flawed. You copy `A` in the second line, which of course copies the `b` member. Also, a `std::forward` will result in a move, only `std::forward` would result in an lvalue. – Xeo Jul 05 '13 at 23:26
  • Well ok before the edit this was incorrect but the template solution using reference collapsing works for the specified case (as far as I can tell by check with `std::is_rvalue_reference` and `std::is_lvalue_reference`). So if there's still something wrong about that answer give me a hint instead of passing a downvote without any comments. – Pixelchemist Jul 09 '13 at 11:16