0

Consider the following code:

#include <iostream>

#define P_(x) std::cout << x << std::endl

class B {
public:
    B() { P_("B::B()"); }
    B(const B&) { P_("B::B(const B&)"); }
    B(B&&) { P_("B::B(B&&)"); }
    ~B() { P_("B::~B()"); }

    B& operator=(const B&) { P_("B::op=(const B&)"); return *this; }
    B& operator=(B&& b) { P_("B::op=(B&&)"); return *this; }
};

class Foo {
public:
    void setB(const B& b) { mB = b; }
private:
    B mB;
};

B genB() {
    return B();
}

int main() {
    Foo f;
    f.setB(genB());
}

Suppose B is a type that is difficult to copy-construct. I'd like to generate some B (with the function genB) and store it in a Foo. Since genB returns a temporary result, I'd expect that a move constructor would be used.

However, when I run the code, I get this output:

B::B()
B::B()
B::op=(const B&)
B::~B()
B::~B()

This clearly shows that two B's get created and destroyed, but that the second is a copy, and not a move of the first.

What is the best way to get move constructors used whenever possible?

  • Do I need to call std::move() somewhere?
  • Do I need a separate overload for a B& and a B&&?
  • Is there something else entirely that I'm missing?
Symaxion
  • 785
  • 7
  • 21

2 Answers2

3

You could overload that setB function:

class Foo {
public:
    void setB(const B& b) { mB = b; }
    void setB(B&& b) { mB = std::move(b); }
private:
    B mB;
};

Or, you can use the "pass by value" way:

class Foo {
public:
    void setB(B b) { mB = std::move(b); }
private:
    B mB;
};

Here, the parameter b will be move constructed when possible or copy constructed otherwise.

aschepler
  • 70,891
  • 9
  • 107
  • 161
0

The first B instance is the one created when creating your Foo instance :

Foo f;

This is because your Foo class has a B member called mB.

The second B instance is the one created by the genB() call.

The assignment operator is called because of the assignment you perform in the Foo::setB function :

mB = b;

Nowhere is there a chance to use a copy or move constructor.

Sander De Dycker
  • 16,053
  • 1
  • 35
  • 40