2

Which of the below two should be preferred and why?

struct X {
    Y data_;
    explicit X(Y&& data): data_(std::forward<Y>(data)) {}
};

vs

struct X {
    Y data_;
    explicit X(Y data): data_(std::move(data)) {}
};
bobah
  • 18,364
  • 2
  • 37
  • 70
  • 2
    POD's do not have user defined constructors! I'd prefer the second one because the first will not bind to lvalues. Also, the first one should be `std::forward(data)`. – Praetorian Mar 11 '14 at 17:46
  • 4
    Please replace `std::forward` with `std::move` in the first one. `std::forward` only makes sense in combination with template parameters. – nosid Mar 11 '14 at 18:52
  • Added template parameter to `forward` – bobah Mar 11 '14 at 19:27
  • @Praetorian As far as I know, a POD can have user-defined constructors (!= aggregate). There can, however, be no user-defined default, copy or move constructors (or dtors). – dyp Mar 11 '14 at 19:39
  • @dyp I was under the impression a POD is an aggregate whose members are also PODs, i.e the requirements are stricter than those for aggregates. Can't check at the moment ... – Praetorian Mar 11 '14 at 19:42
  • @Praetorian Sounds reasonable, but I think a POD is simply a requirement for a certain layout, not for a certain usage. [class]/10 just says "A *POD struct* is a non-union class that is both a trivial class and a standard-layout class, and has no non-static data members of type non-POD struct, non-POD union (or array of such types)." – dyp Mar 11 '14 at 19:46
  • I updated the question to keep the discussion close to the point – bobah Mar 11 '14 at 21:04

1 Answers1

6

The two variants differ in functionality. The following statements work for the second one–but not for the first one:

Y y;
X x(y);

If you are looking for the same functionality, the two variants should look as follows:

struct X
{
    Y data_;
    explicit X(const Y& data) : data_(data) { }
    explicit X(Y&& data) : data_(std::move(data)) { }
};

struct X
{
    Y data_;
    explicit X(Y data) : data_(std::move(data)) { }
};

The first variant saves one move operation, whereas the second variant is less to write. So, the answer is: Use the latter as long as you have no reason to optimize the performance.

nosid
  • 48,932
  • 13
  • 112
  • 139
  • Shouldnt this read "The first variant saves one *copy* operation"? (Namely, when we have an rvalue and can use the move constructor, where the second variant would still have to copy its argument) – Benno Mar 12 '14 at 12:13
  • If we have an _rvalue_, then the parameter _data_ in the second variant will be constructed with the _move constructor_, i.e. the object will moved twice, first from the argument into the parameter, and then from the parameter into the member variable. There is no additional _copy operation_ compared to the first variant. There is only an additional _move operation_. – nosid Mar 12 '14 at 13:23