0
#include <iostream>

class Int {
public:
    explicit Int(int integer) : i(integer) {
        std::cout << "\tInt constructor\n"; 
    }
    Int(const Int& other) {
        std::cout << "\tInt copy constructor\n";
        i = other.i;
    }
    Int& operator=(const Int& other) {
        std::cout << "\tInt copy assignment operator\n";
        i = other.i;
        return *this;
    }
    Int(const Int&& other) {
        std::cout << "\tInt move constuctor\n";
        i = other.i;
    }
    Int& operator=(const Int&& other) {
        std::cout << "\tInt move assignment operator\n";
        i = other.i;
        return *this;
    }
    ~Int() = default;
private:
    int i;
};

struct B {
public:
    explicit B(Int integer) : i(std::move(integer)) {}
private:
    Int i;
};

int main() {
    std::cout << "create B from rvalue\n";
    B b_from_rvalue(Int(6));
    return 0;
}

I expected the Int to be moved to the constructor, then to be moved again when doing std::move.

If I do instead:

B b_from_rvalue(std::move(Int(6)));

Then it does call the move constructor twice.

So it looks to me a lot like return value optimization, but I'm not sure.

The behaviour is the same on gcc and clang with any optimization flag.

  • 1
    `std::move()` is nothing more or less than a type cast. (If I could only remember where I read this...) – Scheff's Cat Dec 05 '19 at 12:46
  • 1
    https://stackoverflow.com/questions/12953127/what-are-copy-elision-and-return-value-optimization – Cory Kramer Dec 05 '19 at 12:46
  • 2
    Your move constructor and assignment operator should accept `Int&&` rather than `const Int&&`. – HolyBlackCat Dec 05 '19 at 12:48
  • 1
    @Scheff "`std::move` produces an xvalue expression that identifies its argument `t`. It is exactly equivalent to a static_cast to an rvalue reference type." from [here](https://en.cppreference.com/w/cpp/utility/move). This what you were referring to? – ChrisMM Dec 05 '19 at 12:48
  • 1
    Try to add `-fno-elide-constructors` compiler flag together with `-std=c++11` or `-std=c++14`. Live demo [here](https://wandbox.org/permlink/3QrNTNLLinaakDWM). – Daniel Langr Dec 05 '19 at 12:51
  • 1
    @ChrisMM I found [Universal References in C++11 -- Scott Meyers](https://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers) where he mentions that `Widget var2 = std::move(var1);` is equivalent to `Widget var2 = static_cast(var1);` although it was not the article I remembered roughly... ;-) – Scheff's Cat Dec 05 '19 at 12:51

0 Answers0