0

I'm using VS Code to compile and debug with g++ in Linux.

Needed includes and usings:

#include <string>
#include <iostream>

using namespace std;

Here is my class which is moveable:

class A {
public:
    A(const string& strA) : strA(strA) {}

    A(const A& a) : A(a.strA) {
    }

    A(A&& a) : A(a.strA) {
        a.strA = "";
    }

    string strA;
};

Example function that returns an instance of A:

A RetA() {
    A a("a");
    A b("bha");

    string ex;
    cin >> ex;
    a.strA += ex;

    return ex == "123" ? a : b;
}

And here is the simple main:

int main() {
    A a(RetA());

    return 0;
}

And returning value in the RetA function is copied, not moved. Why?

On the other hand, if we use "explicitly if" instead of ternary operator in the RetA function:

A RetA() {
    A a("a");
    A b("bha");

    string ex;
    cin >> ex;
    a.strA += ex;

    if (ex == "123")
        return a;

    return b;
}

Then it is moved, not copied. This is already expected behaviour. But it is strange that move operation doesn't work with ternary operator. Should it be like that or is it a bug or something for VS Code etc?

rioV8
  • 24,506
  • 3
  • 32
  • 49
Oğuzhan Türk
  • 360
  • 2
  • 9
  • 21
  • 1
    A possible duplicate of this [thread](https://stackoverflow.com/questions/11914691/copy-elision-move-constructor-not-called-when-using-ternary-expression-in-retur). – rawrex Jun 25 '21 at 07:39
  • Are you sure? Maybe the object is neither copied nor moved. Maybe return value optimization kicks in. It is mandatory, starting in C++17, even before that it was permitted. – Alex Guteniev Jun 25 '21 at 07:42
  • 2
    Key line: *So copy elision is not allowed here, and there is nothing else that says that the lvalue expression can pretend to be an rvalue for overload resolution.* - [Answer](https://stackoverflow.com/a/11915906/14624729). – rawrex Jun 25 '21 at 07:44

1 Answers1

6

The "automatic" move in return statement is limited:

From Automatic move from local variables and parameters:

If expression is a (possibly parenthesized) id-expression that names a variable whose type is either [..]

It is not the case for return ex == "123" ? a : b;.

Then normal way is done, ex == "123" ? a : b return a l-value, so copy happens.

You might do

return std::move(ex == "123" ? a : b);

or

return ex == "123" ? std::move(a) : std::move(b);

to have manual move.

using if allows to follows the above rules with automatic move

if (ex == "123")
    return a;
else
    return b;
Jarod42
  • 203,559
  • 14
  • 181
  • 302