1

I have the following code, which apparently compiles in MSVC and GCC:

#include <iostream>

class Test
{
public:
  Test() = default;
  Test(Test const& other) = delete;
  Test(Test&& other) noexcept = delete;

  Test& operator=(Test const& other) = delete;
  Test& operator=(Test&& other) = delete;

  auto getX() -> int
  {
    return x;
  };
  auto setX(int xz) -> void
  {
    x = xz;
  };

private:
  int x = 42;
};

void something(Test&& thing) {
  thing.setX(44);
  std::cout << thing.getX() << std::endl;
}

int main()
{
  Test a;
  a.setX(3);
  std::cout << "Before call: " << a.getX() << std::endl;
  something(std::move(a));
  std::cout << "After call: " << a.getX() << std::endl;
}

Now, I would have expected this to not compile. Both the move and the copy constructor of Test are deleted. The function something only accepts r-value references. However, it does compile, and this is the output of the program:

Before call: 3
44
After call: 44

The only way that I could think of how it should be possible to pass an object of type Test to a function is by using an l-value reference or const ref. But the way something is defined, it should only accept rvalues, shouldn't it?

Here is the code on compiler explorer: https://godbolt.org/z/rGKdGbsM5

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
bweber
  • 3,772
  • 3
  • 32
  • 57
  • 1
    you cannot prevent someone from getting a reference to an object – 463035818_is_not_an_ai Nov 22 '21 at 15:20
  • Learn this [const& , & and && specifiers for member functions in C++](https://stackoverflow.com/questions/28066777/const-and-specifiers-for-member-functions-in-c) – 273K Nov 22 '21 at 15:22
  • @FrançoisAndrieux: Thanks for the answer. I know that move only casts the object to an rvalue-reference. My misconception was how the argument is passed to a function expecting a && argument. I would have assumed that the argument is moved inside. Instead it is passed as a reference. The only significance of the && in the function signature is that only r-values bind to this overload. If you like you can add your comment as an answer and I will accept it. – bweber Nov 22 '21 at 15:32

1 Answers1

0

rvalue references are just references just like lvalue references. The difference between them is the kind of expression that can be used to initialize them.

std::move casts an lvalue reference to an rvalue reference. It doesn't require the type to be movable. If you try to actually move thing in something then you will get errors.

François Andrieux
  • 28,148
  • 6
  • 56
  • 87