bobah
bobah

Reputation: 18864

C++11 constructor argument: std::move and value or std::forward and rvalue reference

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)) {}
};

Upvotes: 2

Views: 1417

Answers (2)

Mi-La
Mi-La

Reputation: 725

It seems that the first variant only "sometimes" saves on move operation.

#include <iostream>

struct S
{
    S() = default;
    S(const S& other) { std::cout << "copy" << std::endl; }
    S(S&& other) { std::cout << "move" << std::endl; }
};

struct Owner
{
    Owner(S s) : s(std::move(s)) {}
    //Owner(S&& s) : s(std::move(s)) {} // this will "sometimes" save a single move
    S s;
};

S createS()
{
    return S();
}

int main()
{
    std::cout << "owner1:" << std::endl;
    Owner owner1 = Owner(S());

    std::cout << "owner2:" << std::endl;
    Owner owner2 = Owner(createS());

    std::cout << "owner3:" << std::endl;
    S s;
    Owner owner3 = Owner(std::move(s));

    return 0;
}

Try on godbolt

Only use-case owner3 seems to have the two moves. However I agree that second variant is probably better until you measure that it's really a performance issue in your particular application.

Upvotes: 0

nosid
nosid

Reputation: 50044

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.

Upvotes: 6

Related Questions