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.
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.
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.
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).
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:
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With