invalid cast of an rvalue expression

Axel Freyn axel-freyn@gmx.de
Wed May 18 19:21:00 GMT 2011


Hi Oren,
On Wed, May 18, 2011 at 09:42:03AM -0700, Foster Boondoggle wrote:
> 
> Hi Axel - Thanks for the quick reply.
> 
> Here's the problem: The intention is that SqMatrix is nothing more than a
> Matrix with the property that rows = cols. The class declaration 
> class SqMatrix : public Matrix {...}
> reflects this. So, for example, operator * works in exactly the same way for
> SqMatrix as for Matrix, and there should be no need to duplicate the code. 
> Meanwhile, Matrix declares operator * by
> class Matrix { ...
>     Matrix  operator * (const Matrix &) const ; 
> }
OK -- and you define now new member-variables in SqMatrix, I hope?
> Your solution has extra potential overhead due to the guts-copying of the
> Matrix into the new SqMatrix. This could be overcome by using smart_ptr or
> smart_array types, but that all shouldn't be necessary. What is wanted is a
> cast of a base class object (the returned Matrix) to a reference to derived
> class object (to a SqMatrix). However gcc (but not msvc++) rejects it. 
OK, so: to my knowledge gcc (and Ian) are right, msvc is wrong :-) you
are not allowed to do it. 
> 
> I saw Ian's reply, but all it said was "you can't do that". That's not very
> helpful - this code has been working for over a decade, so one would hope
> that the "dotting i's & crossing t's" of increased language rigor would at
> least leave room for a syntactic workaround giving the same (valid) semantic
> result.
Yes, that would be nice. but: Standard-C++ is NOT fully compatible to
pre-standard C++ :-(

However, if you are sure that it works fine, you can do it :-) You can
do everything in C++ .... (and even more if you leave C++ a bit :-))

The secret is: you have to tell the Compiler "dear compiler, I know what
I do. I know, that this memory can be used as SqMatrix, even if you
don't believe so. So just trust me -- and don't verify it" -- and then
you are 100% responsible (e.g. if sizeof(SqMatrix) != sizeof(Matrix),
you have a problem. Or if the Destructor of SqMatrix does NOT destroy
correctly the matrix or something like that, you might introduce memory
errors...

The syntax is:
SqMatrix  operator * (const SqMatrix &sm) const {
    return reinterpret_cast<const SqMatrix &>(
	static_cast<const Matrix &>(*this) * sm
     ); 
}

Here, I use "static_cast" to convert "const SqMatrix &" into "const
Matrix &" -- that's a "legal" conversion derived class -> base class, so
I ask the compiler to verify what I'm doing (that will fail if SqMatrix
would not be derived from Matrix!)

And then I use "reinterpret_cast" to convert the result into a reference
to a const SqMatrix. That is a "illegal" conversion, which can't be
verified by the compiler. Reinterpret_cast does NOT call any conversion
functions e.g. -- and I think the result is implementation defined, so
add a testcase to your program to verify whether this line works as
expected! 


HTH,

Axel


> 
> 
> Axel Freyn wrote:
> > 
> > Hi Oren,
> > On Wed, May 18, 2011 at 07:36:03AM -0700, Foster Boondoggle wrote:
> >> 
> >> Hi Adam99 - Did you ever get a reply to this? I have the exact same
> >> problem
> >> (indeed, with SqMatrix and Matrix, though I had though I wrote the class
> >> many years ago!) I can't seem to get it to compile in any form with the
> >> latest gcc.
> > 
> > Yes, that question was answered by Ian, see e.g.
> > http://old.nabble.com/Re%3A-invalid-cast-of-an-rvalue-expression-p23106343.html
> > The point is: It is illegal C++ :-) 
> > Old compilers (like g++ 4.1.2) accepted such constructs, but the new
> > gcc-versions detect it as failure
> > 
> > In addition: what this line does, is the following:
> >  - take "this", a pointer to a  "const SqMatrix"
> >  - convert it to a Pointer to a "Matrix" (already problematic: you
> >    remove the const-ness here...)
> > Yes, that's old-style C++, but equivalent to a const_cast.
> > 
> >  - take the element and multiply it with "sm"
> >  - convert the pointer to a constant reference to a SqMatrix
> > This used to be interpreted by the compiler as just an instruction to
> > reinterpret the object as being of the derived type.
> >  - create a copy of this reference and return it.
> > How about, just return the object but understand it as being of the
> > derived type.
> > 
> > that sounds a bit complex to me. 
> > 
> > In order to propose a solution, we would need more information (e.g. how
> > are the classes defined? is SqMatrix derived from Matrix? are there any
> > Conversion-Operators / Copy-Constructors defined which can be used for
> > this conversions? 
> > The easiest solution for this code segment would be to add a new
> > copy-constructor to SqMatrix:
> > class SqMatrix {
> >   public:
> >     explicit SqMatrix(const Matrix &m) : ...{
> >      assert(m.Rows() == m.Columns());
> >      ....
> >    }
> > };
> > which verifies that m is really square, and then creates a SqMatrix from
> > m (I added "explicit" in order to block implicit type-conversions Matrix
> > -> SqMatrix -- this constructor has to be called directly).
> > 
> > With that, you could rewrite your code-segment as
> > 
> >       SqMatrix  operator * (const SqMatrix &sm) const {
> >           return SqMatrix(*(const Matrix *)this * sm); }
> > 
> > which would be save (the type-conversion is cleanly done) and portable.
> > (however, as I don't know the full code, may be this solution poses
> > other problems?)
> > 
> > Axel (I'm not adam99 ;-))
> > 
> > ...
> > 
> > 
> 
> -- 
> View this message in context: http://old.nabble.com/invalid-cast-of-an-rvalue-expression-tp23105605p31648660.html
> Sent from the gcc - Help mailing list archive at Nabble.com.
> 



More information about the Gcc-help mailing list