Is it safe to return *this as a reference?

anton_rh picture anton_rh · Feb 27, 2016 · Viewed 10.8k times · Source

Returning reference to this object is often used in assignment operator overloading. It is also used as a base for named parameters idiom which allows to initialize object by chain of calls to setter methods: Params().SetX(1).SetY(1) each of which returns reference to *this.

But is it correct to return reference to *this. What if we call the method returning reference to this for a temporary object:

#include <iostream>

class Obj
{
public:
    Obj(int n): member(n) {}
    Obj& Me() { return *this; }

    int member;
};

Obj MakeObj(int n)
{
    return Obj(n);
}

int main()
{
    // Are the following constructions are correct:
    std::cout << MakeObj(1).Me().member << std::endl;
    std::cout << Obj(2).Me().member << std::endl;
    Obj(3).Me() = Obj(4);

    return 0;
}

Answer

JVApen picture JVApen · Feb 27, 2016

Yes, it is safe to return *this. The easy case is when this is not a temporary, though even when it is, this should be possible:

Temporary objects are destroyed as the last step in evaluating the full-expression (1.9) that (lexically) contains the point where they were created. This is true even if that evaluation ends in throwing an exception (C++03 §12.2/3).

In other words, until you reach a semi-colon everything should be fine (in theory).

So following code should work:

std::cout << MakeObj(1).Me().member << std::endl;

While this should not work:

const Obj &MakeMeObj(int n) { return Obj(n).Me(); }
std::cout << MakeMeObj(1).member << std::endl;

This is logical, as you are returning a reference to a temporary. Most compilers warn/error on this, though if you code gets to complex, this is something to watch out for.

Personally, I would prevent calling these methods on a temp object to enforce API users to think about the lifetime of the object. Which can be done by overloading your method: (If your compiler supports it already)

Obj &Me() & { return *this; }
Obj &Me() && = delete;