Search code examples
c++11rvalue-referencethis-pointer

Return "this" as rvalue


The following code does, as expected, not compile

#include <iostream>

class A
{

  public:

    A() = default;
    ~A() = default;

    A(const A&) = delete;
    A(A&&) = delete;

    A& operator=(const A&) = delete;
    A& operator=(A&&) = delete;

    A& operator<<(const int i)
    {
      std::cout << "operator<< called" << std::endl;
      return *this;
    }

};

void foo(A&& a)
{
  std::cout << "foo called" << std::endl;
}

int main()
{
  A a; a << 14;
  foo(std::move(a)); // works fine

  foo(A() << 14);    // does not compile

  return 0;
}

Changing the class A to

class A
{

  public:

    A() = default;
    ~A() = default;

    A(const A&) = delete;
    A(A&&) = delete;

    A& operator=(const A&) = delete;
    A& operator=(A&&) = delete;

    A& operator<<(const int i) &
    {
      std::cout << "operator<< called on lvalue" << std::endl;
      return *this;
    }

    A&& operator<<(const int i) &&
    {
      std::cout << "operator<< called on rvalue" << std::endl;
      return std::move(*this);
    }


};

makes the program compile. However, return rvalues with std::move is usually not a good idea, since it will return dangling references or prevents the compiler to do certain optimizations.

Is the described case one of the few exception from the rule of thumb "do not return by rvalue" or should the issue be resolved differently?

Great thanks!


Solution

  • This code is perfectly valid and safe. As your object is already an rvalue in

    A&& operator<<(const int i) &&
    

    casting it to rvalue again (with move) will not change security of the code. NRVO optimization will not take place in this case so speed of the code is unlikely to be affected.

    So as you formulate it I'd say "yes, this is an exception to the rule"

    Also this rule is not universal: if you understand what's going on (which is why you asked this question) you can rely on your good sense instead of it.