Topic: Compiler bug throwing the result of a function call.
Author: sbnaran@localhost.localdomain (Siemel Naran)
Date: 1999/05/21 Raw View
On 13 May 99 21:35:55 GMT, Marcelo Cantos <marcelo@io.mds.rmit.edu.au> wrote:
>The question I have for comp.std.c++, however, is whether it is legal
>to throw a reference to a local object. Will doing so result in a
>copy of the object being thrown, or will all hell break loose?
It is impossible to throw a reference to an object. The statement
throw object;
always calls Object::Object(const Object&) to make a copy of 'object'
-- which may be a local or global -- and throws this copy. Of course,
the copy may be optimized away wherever appropriate. Eg,
int f() { Object o; throw o; return o.action(); }
// needs Object's copy constructor to copy 'o' into the exception space
int f(bool b) { if (b) throw Object(); return Object().action(); }
// no need for Object's copy constructor
// create exception object directly in exception space
// kind of like the return value optimization
>class X {
>public:
> X& x() { return *this; }
> X() { cerr << "Construct " << this << ".\n"; }
> X(const X& x) { cerr << "Copy " << this << " <= " << &x << ".\n"; }
> X& operator=(const X& x)
> { cerr << "Assign " << this << " <= " << &x << ".\n"; }
> ~X() { cerr << "Destruct " << this << ".\n"; }
>};
>
>int main ()
>{
> try
> {
> throw X().x();
> }
> catch(...) { }
>}
TRY BLOCK:
The "X()" creates a local X object.
The ".x()" returns a reference to this local X object.
Now we are ready to leave the function...
Invoke X's copy constructor to local object into exception space.
Destroy the local object.
Summary: one call to X(), one call to X::X(const X&), one call to X::~X()
CATCH BLOCK:
The catch block catches by reference. So nothing to do.
(If catch by value, a second call to the copy constructor forced.)
As the catch block doesn't rethrow, delete the caught object at end of block.
Summary: one call to X::~X().
Como follows this scheme literally and the output is
Construct 0xbffffbef.
Copy 0x80583e0 <= 0xbffffbef.
Destruct 0xbffffbef.
Destruct 0x80583e0.
The first three lines happen in the try block. The last line happens
in the catch block. (Put a statement "cout << "catch\n";" in the catch
block to prove this).
In view of the fact that X::x() is inline, an optimizing compiler will
realize that "X().x()" is the same as "X()", and thus elide a call to
the copy constructor of X. The result of the program should then be
Construct 0xbffffbef. // in try block
Destruct 0xbffffbef. // in catch block
But the output of egcs is
Construct 0xbffffc60.
Copy 0x80592a0 <= 0xbffffc64.
Destruct 0xbffffc64.
Destruct 0xbffffc60.
Destruct 0x80592a0.
This is clearly a bug.
--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: James.Kanze@dresdner-bank.com
Date: 1999/05/18 Raw View
n article <bgiu9xhfo6.fsf@io.mds.rmit.edu.au>,
Marcelo Cantos <marcelo@io.mds.rmit.edu.au> wrote:
> I originally posted the following code to the egcs mailing list on
> egcs.cygnus.com, thinking it was a compiler bug. I received a reply
> stating that throwing a reference to a local object was ill-defined,
> which statisfied me at first. After some deliberations I am not so
> sure, so I thought I would post here for clarification.
Well, throwing a reference is certainly ill-defined -- you throw an
object, not a reference. But it is ill-defined because there is simply
no way to do it.
The explination of a throw-expression (in 15.1) doesn't directly specify
that the argument is an rvalue, but it does say that the argument is
used to initialize a temporary *object*; an initializer for an object is
normally an rvalue, and I would expect the rvalue to lvalue conversion
to take place. The actual text is: "A throw-expression initializes a
temporary object, the type of which is determined by removing any
top-level cv-qualifiers from the static type of the operand of throw and
adjusting the type from "array of T" or "function returning T" to
"pointer to T" or "pointer to function returning T", respectively." It
would be nice if it were clearer concerning references, but since a
reference is *not* an object, I think the intent is clear; the "type" of
the operand is the rvalue type.
> According to the reply on the mailing list, the throw statement is
> undefined because it is making a copy of the reference, not the
> object. This seems odd to me (the notion of copying a reference, that
> is).
A reference can be used to initialize another reference. In this case,
however, the standard clearly says that what is thrown in an object, not
a reference.
> Furthermore, later experiments verified that throwing a
> reference fails, even when the reference is to a global object, so
> there is almost certainly a failt in egcs.
>
> The question I have for comp.std.c++, however, is whether it is legal
> to throw a reference to a local object. Will doing so result in a
> copy of the object being thrown, or will all hell break loose?
IMHO, you cannot throw a reference, period, because the rvalue to lvalue
conversion implicit in initializing an object will dereference the
reference. On the other hand, I do find it problematic that the cited
passage doesn't mention this conversion (although you cannot throw an
*object* without it).
--
James Kanze mailto:
James.Kanze@dresdner-bank.com
Conseils en informatique orient e objet/
Beratung in objekt orientierter
Datenverarbeitung
Ziegelh ttenweg 17a, 60598 Frankfurt, Germany Tel. +49 (069) 63 19 86
27
--== Sent via Deja.com http://www.deja.com/ ==--
---Share what you know. Learn what you don't.---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Marcelo Cantos <marcelo@io.mds.rmit.edu.au>
Date: 1999/05/13 Raw View
I originally posted the following code to the egcs mailing list on
egcs.cygnus.com, thinking it was a compiler bug. I received a reply
stating that throwing a reference to a local object was ill-defined,
which statisfied me at first. After some deliberations I am not so
sure, so I thought I would post here for clarification.
According to the reply on the mailing list, the throw statement is
undefined because it is making a copy of the reference, not the
object. This seems odd to me (the notion of copying a reference, that
is). Furthermore, later experiments verified that throwing a
reference fails, even when the reference is to a global object, so
there is almost certainly a failt in egcs.
The question I have for comp.std.c++, however, is whether it is legal
to throw a reference to a local object. Will doing so result in a
copy of the object being thrown, or will all hell break loose?
----------------------------------------------------------------------
/* exception.cc
This file illustrates a mismatch between constructors, copy
constructors and destructors for an object that is thrown in an
exception:
% uname -a
Linux foobar 2.0.36 #1 Tue Oct 13 22:17:11 EDT 1998 i686 unknown
% g++ -v
Reading specs from /usr/local/lib/gcc-lib/i686-pc-linux-gnu/egcs-2.91.66/specs
gcc version egcs-2.91.66 19990314 (egcs-1.1.2 release)
% g++ -o exception exception.cc
% ./exception
Construct 0xefffed68.
Copy 0x37330 <= 0xefffed70.
Destruct 0xefffed70.
Destruct 0xefffed68.
Destruct 0x37330.
%
Notes:
1. The copy constructor is being passed a non-existent object.
2. Remove the '.x()' in the thrown expression and it works.
3. Modify X::x() to return X instead of X& and it works.
4. This also fails on a SPARC Solaris 2.5.1 with egcs 1.1.1.
*/
#include <iostream>
#include <exception>
class X {
public:
X& x() { return *this; }
X() { cerr << "Construct " << this << ".\n"; }
X(const X& x) { cerr << "Copy " << this << " <= " << &x << ".\n"; }
X& operator=(const X& x)
{ cerr << "Assign " << this << " <= " << &x << ".\n"; }
~X() { cerr << "Destruct " << this << ".\n"; }
};
int main ()
{
try
{
throw X().x();
}
catch(...) { }
}
----------------------------------------------------------------------
Cheers,
Marcelo
--
http://www.simdb.com/~marcelo/
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: gbush@my-dejanews.com
Date: 1999/05/14 Raw View
In article <bgiu9xhfo6.fsf@io.mds.rmit.edu.au>,
Marcelo Cantos <marcelo@io.mds.rmit.edu.au> wrote:
> I originally posted the following code to the egcs mailing list on
> egcs.cygnus.com, thinking it was a compiler bug. I received a reply
> stating that throwing a reference to a local object was ill-defined,
> which statisfied me at first. After some deliberations I am not so
> sure, so I thought I would post here for clarification.
There are no problems with your code except for operator << is not
defined for const X*, but that was not your question.
When the exception is thrown (throw X().x();) the following happens:
1) temporary object #1 is created with X();
2) member function is called x() returning X&;
3) copy-constructor is invoked X(const X&) to create temporary object #2
(15.1.3) that must persist till the exit of the catch handler(15.1.4);
4) destructor for temporary #1 is called;
5) catch handler is executed;
Therefore, when catch handler is entered it receives a newly created
(on stage 3) temporary object #2 , not the reference on destroyed
object #1.
In the light of this I conclude that egcs has a bug in implementation.
I verified BCB, it works correctly.
Gene.
--== Sent via Deja.com http://www.deja.com/ ==--
---Share what you know. Learn what you don't.---
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]