Move semantics and std::move

Viewed 112

I have a general question about move semantics. Yesterday I just played around to get more comfortable with this topic. Here I added copy and move constructor operators, that simply log to the console:

#include <iostream>

class Test {    
public:
  const char* value = "HI";
  Test(){
     std::cout << "Default Constructed\n";
  }
  Test(Test &&source) { 
     std::cout << "Move Constructed\n";
  }
  Test(const Test &source) {
     std::cout << "Copy Constructed\n";
  }
};    

Now when I call

void showMe(Test&& test) {
  std::cout << test.value;
}

int main() {
  Test test1;
  // Test test2{test1};
  showMe(std::move(test1));

  return 0;
}

The console logs out:

> Default Constructed

> HI

Which is clear to me, since we are just moving the ownership to showMe. But why wasn't the Test's move constructor operator be called?

But now, if I change showMe function into

void showMe(Test test) {
  std::cout << test.value;
}

the console shows:

> Default Constructed

> Move Constructed

> HI

So my question is, why was the Move constructor operator not executed in the first case, but in the second? I usually thought in the first case, the Test's move operator should execute. What are the differences between those two cases mentioned?

3 Answers

But why wasn't the Test's move constructor operator be called?

Because you keep operating on the same object via a reference to an rvalue. No new object is being constructed, hence no constructor is necessary.

You could conceivably keep passing that reference down, just like you can do with a regular reference or a reference to const - the very nature of references is that they're not objects.

In your second example, the parameter to the function is a value, and in order to construct that value, the second constructor needs to fire.

In the first place you pass a reference. Therefore, no new object needs to be created.

In your function:

void showMe(Test test)

the formal argument is passed by value. That is the reason the move constructor gets called. Passing by value means that the parameter is copied into the function. That calls the move constructor.

In the second case:

void showMe(Test&& test)

the formal argument is passed by reference hence no new object needs to be created and therefore no constructor gets called.

Related