5

I've been having difficulties understanding move constructors in C++. I have made a simple class with a default constructor, copy constructor, move constructor and destructor. Also, I have defined a function with two overloads, one accepts a reference to that class and one accepts an rvalue reference to that class. My test code is below.

#include <iostream>


class c {

public:

    c() {
        std::cout << "default constructor" << std::endl;
    }

    c(const c& s) {
        std::cout << "copy constructor" << std::endl;
    }

    c(c&& s) {
        std::cout << "move constructor" << std::endl;
    }

    ~c() {
        std::cout << "destructor" << std::endl;
    }

};

void f(c& s) {
    std::cout << "passed by reference" << std::endl;
}

void f(c&& s) {
    std::cout << "passed by rvalue reference" << std::endl;
}

int main() {

    c s1; // line 1
    std::cout << "\n";
    c s2(s1); // line 2
    std::cout << "\n";
    c s3(c()); // line 3

    std::cout << "\n";

    f(s1); // line 4
    std::cout << "\n";
    f(c()); // line 5

    getchar();
    return 0;

}

The output I'm getting is not what I was expecting. Below is the output I'm getting from this code.

default constructor

copy constructor

passed by reference

default constructor
passed by rvalue reference
destructor

I can understand the outputs from all lines except line 3. On line 3, which is c s3(c());, c() is an rvalue so I'd expect that s3 would be move constructed. But the output doesn't show that it is move constructed. On line 5, I'm doing the same thing and passing an rvalue to the function f() and it indeed calls the overload that accepts an rvalue reference. I'm very confused and would appreciate any information on this.

Edit: I am able to call the move constructor if I do c s3(std::move(c())); but am I not already passing an rvalue to s3? Why would I need std::move?

M.M
  • 138,810
  • 21
  • 208
  • 365
Deniz
  • 509
  • 7
  • 26
  • 2
    @NathanOliver That's not really a duplicate of this one. What's happening here is the Most Vexing Parse, not copy elision. – Angew is no longer proud of SO Jun 02 '17 at 14:27
  • @Angew Good call. Missed that. – NathanOliver Jun 02 '17 at 14:31
  • @Angew What I actually was trying to do was constructing an object through its move constructor and when NathanOliver directed me to the other question, I really thought this was a duplicate. I didn't even notice the statement on line 3 was a function signature until you have pointed out. I have never heard of most vexing parse either, so thank you for sharing that with me; I'll be reading on it to learn what it is. – Deniz Jun 02 '17 at 14:52

2 Answers2

9

The reason why you don't see any output from line 3 is that it declares a function, not a variable. This is due to an ambiguity called Most Vexing Parse.

Compare c s3(c()) with int foo(int ()), which, thanks to implicit type adjustments, is the same as int foo(int (*f)()).

To get around this, use brace initialisation (which was actually introduced in C++11 partly for this very reason):

c s3(c{});

// or

c s3{c()};

// or

c s3{c{}};
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
  • Thank you for your informative answer. Both this and also M.M's answer below answer my question. However, apparently you were a minute earlier than they were, so I'll accept your answer. Thank you and M.M for your time and help. – Deniz Jun 02 '17 at 14:48
5

c s3(c()); does not construct any object. It is a function declaration. The function is called s3, the return type is c, and the parameter type is "pointer to function taking no parameters and returning c". So you get no output, since a function declaration does not call any functions.

To avoid this sort of thing you can use list initialization, c s3{c()}; is probably more in line with what you had in mind.

M.M
  • 138,810
  • 21
  • 208
  • 365
  • +1 for info 'parameter type is "pointer to function taking no parameters and returning c"'. if it were `c(x)` then parameter type is `c` and name is `x` – Yusuf R. Karagöz Jun 02 '17 at 14:57