Topic: Question about derived exceptions
Author: sbnaran@fermi.ceg.uiuc.edu (Siemel Naran)
Date: 1999/01/25 Raw View
On 25 Jan 99 19:26:56 GMT, Martijn Lievaart <nobody@orion.nl> wrote:
>I have a question regarding the catching of exceptions by a base type. I try
>to catch by reference, to avoid slicing.
When throwing a new exception (as opposed to re-throwing),
throw Error();
a copy constructor Error::Error(const Error&) is required. This
is because the statement Error() creates a local unnamed Error
object, and the throw copies this local into the exception space.
The compiler can optimize away the local unnamed object by putting
the Error object directly in the exception space. Still, an
accessible copy constructor and destructor is required. Therefore
void f(bool cond)
{
if (cond) throw Error();
// can create Error object directly in exception space
return;
}
The reason for this rule is that in general, you may throw a
named local object, and in this case, a copy is absolutely
necessary.
void f(bool cond)
{
Error e1;
if (cond) throw e1;
// must return a copy of 'e1'
// so call to Error::Error(const Error&) is forced
return e1.f();
}
> // This throw always works as expected
> //throw ebase();
By the above reasoning -- namely ebase::ebase(const ebase&) should
be accessible -- this should give a compile error once you uncomment
it.
>// If I make this public, the problem goes away
>//public: // LINE 1
> explicit ebase(const ebase & e) {}
It seems that the copy constructor should be non-explicit too,
otherwise how can the compiler use it to implicitly make
copies? (Well, I see that you done "#define explicit", but
why did you do this?)
Needed to fix up some stuff. Leave out the 'explicit' stuff,
and make operator= return something.
------------------------------------------------------------
//#include <iostream>
#include <iostream.h>
#define std
class ebase
{
protected:
ebase() {}
// If I make this public, the problem goes away
//public: // LINE 1
ebase(const ebase & e) {}
public:
virtual void print() { std::cout << "base" << std::endl; }
private:
void operator=(const ebase&); // not-implemented
};
class ederived : public ebase
{
public:
ederived() {}
ederived(const ederived & e) {}
virtual void print() { std::cout << "derived" << std::endl; }
private:
void operator=(const ederived&); // not-implemented
};
int main()
{
try
{
// This throw always works as expected
//throw ebase();
// This throw gives problems
throw ederived();
}
// This catch always works as expected
//catch(ederived &e)
//{
// std::cout << "derived!" << std::endl;
//}
// This catch doesn't fire in VC when copy
// constructor of base
// is protected, but does when it is public!
catch(ebase& e)
{
std::cout << "Good!" << std::endl;
e.print();
}
catch(...)
{
// Should never come here...
std::cout << "Bad!" << std::endl;
}
return 0;
}
------------------------------------------------------------
>I obtained the following results, depending if LINE 1 is commented out
>(protected) or not commented out (public).
>
>Compiler public protected
>------------+-------------+----------
>VC 6.0 |Good, derived|Bad!
>------------+-------------+----------
>gcc 2.7.2.1 |Bad! |Bad!
>------------+-------------+----------
>Sun 4.2 |Good, derived|Good, derived
Yes, egcs outputs "Bad!".
I've been having problems with egcs too as regards catching Base
and Derived objects by reference. I think it's a bug in egcs.
When you throw a Derived object, the catch clause catch(Base&)
does not catch it. The result should be "Good, derived".
Also, in the catch clause
catch(E&) { ... }
the standard requires that class E be fully defined. This is
necessary for the compiler to know which catch handler to use.
Eg,
// main.c
try { throw Derived(); }
catch (Base&) { }
catch (Derived&) { }
If class Base and class Derived are defined in their entirety,
then the compiler knows how to catch a Derived object: just
use the first handler. A good compiler should also give you
the warning, "first handler hides the second -- ie, all
'Base' and 'Derived' objects will be handled by the first
catch clause".
The fact that egcs can compile main.c without knowing the
definitions of Base and Derived suggests that it is compiling
incorrectly.
--
----------------------------------
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: "Martijn Lievaart" <nobody@orion.nl>
Date: 1999/01/25 Raw View
I have a question regarding the catching of exceptions by a base type. I try
to catch by reference, to avoid slicing.
Regard the following code (the first 4 lines make Sun 4.2 and gcc compile
this as well):
//#include <iostream>
#include <iostream.h>
#define std
#define explicit
class ebase
{
protected:
explicit ebase() {}
// If I make this public, the problem goes away
//public: // LINE 1
explicit ebase(const ebase & e) {}
public:
virtual void print() { std::cout << "base" << std::endl; }
private:
operator=(const ebase&); // not-implemented
};
class ederived : public ebase
{
public:
explicit ederived() {}
explicit ederived(const ederived & e) {}
virtual void print() { std::cout << "derived" << std::endl; }
private:
operator=(const ederived&); // not-implemented
};
int main()
{
try
{
// This throw always works as expected
//throw ebase();
// This throw gives problems
throw ederived();
}
// This catch always works as expected
//catch(ederived &e)
//{
// std::cout << "derived!" << std::endl;
//}
// This catch doesn't fire in VC when copy
// constructor of base
// is protected, but does when it is public!
catch(ebase& e)
{
std::cout << "Good!" << std::endl;
e.print();
}
catch(...)
{
// Should never come here...
std::cout << "Bad!" << std::endl;
}
return 0;
}
I obtained the following results, depending if LINE 1 is commented out
(protected) or not commented out (public).
Compiler public protected
------------+-------------+----------
VC 6.0 |Good, derived|Bad!
------------+-------------+----------
gcc 2.7.2.1 |Bad! |Bad!
------------+-------------+----------
Sun 4.2 |Good, derived|Good, derived
I would expect the result to be Good, derived in all cases. I have the
feeling I'm missing something completely here.
Even if the copy constructor is needed here (I don't see why), why doesn't
the compiler complain?
Can anyone shed some light here?
Thanks in advance,
Martijn
--
My reply-to address is intentionally set to /dev/null
reply to mlievaart at orion in nl
---
[ 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 ]