Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it safe to return a casted reference?

Let Point be a class whose instances can be explicitly casted to a wxPoint:

class Point{
private:
    int x;
    int y;
public:
    explicit operator wxPoint() const
    {
        return wxPoint(x, y);
    }

    // More stuff
}

I have a function that returns a reference to an object of type Point. The header of such a function is:

const Point& GetPoint();

My question: is it safe to define the following Foo function?

const wxPoint& Foo() const{
    return (wxPoint&) GetPoint();
}

First I implemented Foo with return (wxPoint) GetPoint();, but that created a new (local) object and therefore a useful warning is triggered. The code shown here compiles without warnings.

All the information I found on this kind of casting refers to inherited classes, which is not the case here.

An explanation of what is exactly going on when casting a reference in this way would be really appreciated.

like image 600
Alejandro Avatar asked Jan 17 '17 13:01

Alejandro


People also ask

What happens if you return a reference?

Functions in C++ can return a reference as it's returns a pointer. When function returns a reference it means it returns a implicit pointer.

What does it mean to return a reference?

It means you return by reference, which is, at least in this case, probably not desired. It basically means the returned value is an alias to whatever you returned from the function. Unless it's a persistent object it's illegal.

How does return by reference work?

Example: Return by Reference Hence, this function returns a reference of the variable num . The return statement is return num; . Unlike return by value, this statement doesn't return value of num , instead it returns the variable itself (address).


3 Answers

Actually your conversion operator is never called. You are returning a reference to a point instance from GetPoint. Later you used a C style cast that in your case will be equivalent to a reinterpret_cast<> (see here). You are casting a reference to Point into a reference to wxPoint, and the two are completely unrelated types. On the other hand any operation on the returned reference is undefined behavior.

My suggestion is to always use C++ cast operators. They have benefits:

  • C++ style casts are checked by the compiler.
  • C++ style casts can be searched easily.
  • C++ style casts express the intent of the programmer.
like image 141
MRB Avatar answered Oct 23 '22 17:10

MRB


The other answers have already explained that casting Point& to wxPoint& simply lies to the compiler, telling it that the object the reference is bound to is a wxPoint object, which is not true. Your program will have undefined behaviour if you try to access a wxPoint object through that reference, because it isn't bound to a wxPoint object. Sometimes when you lie to the compiler it can't give you warnings and just has to trust that you're not doing something crazy.

The fix is to stop trying to return a reference to an object that doesn't exist:

wxPoint Foo() const {
    return GetPoint();
}

This will use your conversion operator to construct a wxPoint and return that by value, which is OK. Trying to return by reference when there is nothing to bind the reference to is not OK.

like image 27
Jonathan Wakely Avatar answered Oct 23 '22 16:10

Jonathan Wakely


Casting a reference into an unrelated reference type is not safe. While the cast itself has no side-effects, accessing the original object through the reference of another type has undefined behaviour (unless type aliasing rules provide an exception, like they do in the case of char but that does not apply here since standard specifies no such exception for wxPoint).

The conversion operator is not involved and makes no difference.


An explanation of what is exactly going on when casting a reference in this way would be really appreciated.

The "C style" cast does one of const_cast, static_cast or reinterpret_cast or their combination, in that order of preference. There are no static_cast that apply to unrelated references.

Only thing that applies to converting const Point& into wxPoint& is reinterpret_cast followed by const_cast. reinterpret_cast does:

6) An lvalue expression of type T1 can be converted to reference to another type T2. The result is an lvalue or xvalue referring to the same object as the original lvalue, but with a different type. No temporary is created, no copy is made, no constructors or conversion functions are called. The resulting reference can only be accessed safely if allowed by the type aliasing rules (see below)


The code shown here compiles without warnings.

Using reinterpret_cast is like telling the compiler that you know what you're doing might seem bonkers, but not to worry, you know what you're doing so no need to warn about it. Using it should be done with great care.

Since C style cast may do reinterpret_cast implicitly, the need for great care applies to it as well.

like image 4
eerorika Avatar answered Oct 23 '22 17:10

eerorika