Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is the move constructor called here?

Here is a code sample from a C++ quiz:

#include <iostream>
struct X {
    X(const char *) { std::cout << 1; }
    X(const X &) { std::cout << 2; }
    X(X &&) { std::cout << 3; }
};

X f(X a) {
    return a;
}

X g(const char * b) {
    X c(b);
    return c;
}

int main() {
    f("hello");
    g("hello");
}

What will be the output of the program?

I think this way:

  1. f(X a) is called, and the constructor implicitly converts const char* to X, so the output is 1
  2. As we don't have an object to store the return value in, the return value is discarded, no output
  3. g(const char*) is called, and X c(b) X(const char*) The output is 1
  4. The return value is one more time discarded - no output

So the answer is 11. The answer which is given to the quiz is 131. The answer, which I get with g++ 4.4.4-13 is 121.

It is said that this code was compiled with this command:

g++ -std=c++11 -Wall -Wextra -O -pthread

Where does the middle number come from? And why can it be 3 or 2?

like image 851
DoctorMoisha Avatar asked Aug 12 '15 07:08

DoctorMoisha


People also ask

What do you mean by move constructor?

Move constructor moves the resources in the heap, i.e., unlike copy constructors which copy the data of the existing object and assigning it to the new object move constructor just makes the pointer of the declared object to point to the data of temporary object and nulls out the pointer of the temporary objects.

What is move assignment in C++?

In the C++ programming language, the move assignment operator = is used for transferring a temporary object to an existing object. The move assignment operator, like most C++ operators, can be overloaded. Like the copy assignment operator it is a special member function.

Why should move constructor be Noexcept?

noexcept is nice for two reasons: The compiler can optimize a little better because it doesn't need to emit any code for unwinding a call stack in case of an exception, and. It leads to incredible performance differences at runtime for std::vector (and other containers, too)

What is move constructor and assignment operator?

The move constructor and move assignment operator are simple. Instead of deep copying the source object (a) into the implicit object, we simply move (steal) the source object's resources. This involves shallow copying the source pointer into the implicit object, then setting the source pointer to null.


1 Answers

In theory, this can print any of 131, 13313, 1313, and 1331. It's pretty silly as a quiz question.

  • f("hello");:

    • "hello" is converted to a temporary X via the converting constructor, prints 1.
    • The temporary X is used to initialize the function argument, calls the move constructor, prints 3. This can be elided.
    • x is used to initialize the temporary return value, calls the move constructor, prints 3. It's a function parameter, so no elision is allowed, but the return is an implicit move.
  • g("hello");

    • "hello" is used to construct c via the converting constructor, prints 1.
    • c is used to initialize the temporary return value, calls the move constructor, prints 3. This can be elided.

Remember that functions always have to construct the thing they return, even if it's just discarded by the calling code.

As to printing 2, that's because the ancient compiler you are using doesn't implement the implicit-move-when-returning-a-local-variable rule.

like image 179
T.C. Avatar answered Oct 03 '22 03:10

T.C.