exceptions

J

Josefo

Hello. Here I am again trying to understand the examples of a C++
tutorial. When compiling the original source code:

// standard exceptions
#include <iostream>
#include <exception>
using namespace std;

class myexception: public exception
{
// virtual const char* what() const
char* what()
{
return "My exception happened";
}
} myex;

int main () {
try
{
throw myex;
}
catch (exception& e)
{
cout << e.what() << endl;
}
return 0;
}

I get this:

11myexception

which obviously is not the desired answer. I modified slightly the
code, just writing as type of the argument of the "catch" function the
derived class (myexception) , instead the "parent" one (exception) in
which case I am forced to declare the object function "what" as
public (reason for the difference with respect to the former case ???):


// standard exceptions
#include <iostream>
#include <exception>
using namespace std;

class myexception: public exception
{
// virtual const char* what() const

public:
char* what()
{
return "My exception happened";
}
} myex;

int main () {
try
{
throw myex;
}
catch (myexception& e)
{
cout << e.what() << endl;
}
return 0;
}

Now I get the right answer:

My exception happened

Can someone explain to me the reason of this. I would rather expect
that the type of the parent class could be used for the argument of the
calling function . Or not?

regards
 
M

mlimber

Josefo said:
Hello. Here I am again trying to understand the examples of a C++
tutorial. When compiling the original source code:

// standard exceptions
#include <iostream>
#include <exception>
using namespace std;

class myexception: public exception
{
// virtual const char* what() const
char* what()

This does not override the function in std::exception because you
changed the signature. Delete the line above and uncomment the line
above that, and then you need only to make it public (cf.
http://www.parashift.com/c++-faq-lite/proper-inheritance.html#faq-21.1).
{
return "My exception happened";
}

} myex;

Don't create an instance here. Create it where you throw.
int main () {
try
{
throw myex;

throw myexception();
}
catch (exception& e)

Prefer to catch by const reference:

catch (const exception& e)
{
cout << e.what() << endl;
}
return 0;
}

I get this:

11myexception

which obviously is not the desired answer. I modified slightly the
code, just writing as type of the argument of the "catch" function the
derived class (myexception) , instead the "parent" one (exception) in
which case I am forced to declare the object function "what" as
public (reason for the difference with respect to the former case ???):


// standard exceptions
#include <iostream>
#include <exception>
using namespace std;

class myexception: public exception
{
// virtual const char* what() const

public:
char* what()
{
return "My exception happened";
}
} myex;

int main () {
try
{
throw myex;
}
catch (myexception& e)
{
cout << e.what() << endl;
}
return 0;
}

Now I get the right answer:

My exception happened

Can someone explain to me the reason of this. I would rather expect
that the type of the parent class could be used for the argument of the
calling function . Or not?

You can (and often should) use the parent class to catch. Just fix your
exception class as I describe above.

Cheers! --M
 
J

Josefo

mlimber said:
This does not override the function in std::exception because you
changed the signature.

Hello. Can you explain me what do you mean by "changing signature"?.
Delete the line above and uncomment the line
above that, and then you need only to make it public (cf.
http://www.parashift.com/c++-faq-lite/proper-inheritance.html#faq-21.1).

. I did it. It does not yet work. I should eliminate the last "const"
in the line to be uncommented (on the other hand it has no meaning and
should be an error, am I right?).
About the need to make it public: there is a public inheritance from
exception to myexception, therefore all public members of the base
class should be also public for the derived one, right? So, why should
I declare as public the "what" member function which supposedly is
public (or not?) in the base class?.
Don't create an instance here. Create it where you throw.


throw myexception();


Prefer to catch by const reference:

catch (const exception& e)
You can (and often should) use the parent class to catch. Just fix your
exception class as I describe above.

Cheers! --M

I tried to do as uou suggest, but with no results. By the way, as far
as I know (very little, evidently..) the "virtual" word should only be
used when the declaration of the virtual function is made in the base
class, not when defined in a derived class declaration. right? In fact,
when I leave it it makes no difference (apparently, at least), it gives
no error at compilation but the result is the same ( the output is:
11myexception)

Here is the code:

// standard exceptions
#include <iostream>
#include <exception>
using namespace std;

class myexception: public exception
{
// virtual const char* what() const
public:
const char* what()

// char* what()
{
return "My exception happened";
}
//} myex;
};

int main () {
try
{
// throw myex;
throw myexception();

}
// catch (exception& e)
catch (const exception& e)
{
cout << e.what() << endl;
}
return 0;
}

Cheers
Josefo
 
M

mlimber

Josefo said:
Hello. Can you explain me what do you mean by "changing signature"?.

The signature of the what function in std::exception is:

virtual const char* what() const

but the signature of your function is different:

char* what()

Virtual is optional in your override, but the consts are not.
. I did it. It does not yet work.

User error, methinks. This code works for me:

#include <iostream>
#include <exception>
using namespace std;

class myexception : public exception
{
public:
virtual const char* what() const
{
return "My exception happened";
}
};

int main()
{
try
{
throw myexception();
}
catch( const exception& e )
{
cout << e.what() << endl;
}
return 0;
}
I should eliminate the last "const"
in the line to be uncommented (on the other hand it has no meaning and
should be an error, am I right?).

No. See
About the need to make it public: there is a public inheritance from
exception to myexception, therefore all public members of the base
class should be also public for the derived one, right? So, why should
I declare as public the "what" member function which supposedly is
public (or not?) in the base class?.

Because you are *changing* its access. This is permissible but evil.
See
I tried to do as uou suggest, but with no results. By the way, as far
as I know (very little, evidently..) the "virtual" word should only be
used when the declaration of the virtual function is made in the base
class, not when defined in a derived class declaration. right? In fact,
when I leave it it makes no difference (apparently, at least), it gives
no error at compilation but the result is the same ( the output is:
11myexception)

The virtual keyword is optional. Personally, I prefer to put it in
derived classes to remind me that the function in question is
overriding a function from a base class.
Here is the code:

// standard exceptions
#include <iostream>
#include <exception>
using namespace std;

class myexception: public exception
{
// virtual const char* what() const
public:
const char* what()

Without making this a const member function (that's what the const at
the end does), you have unintentionally created a const overload (see
<http://www.parashift.com/c++-faq-lite/const-correctness.html#faq-18.12>)
that does not replace std::exception::what().

It's like if you did this:

struct Base
{
virtual void f( int ) { /*...*/ }
};

struct Derived : Base
{
virtual void f( double ) { /*...*/ }
};

Derived has not actually override f(int) because you changed the
function signature. So...

void Foo( Base& pb, Derived& pd )
{
pb.f( 1 ); // ok: calls Base::f(int)
pd.f( 1 ); // ok: calls Base::f(int)

pb.f( 1.1 ); // compile-time error!
pd.f( 1.1 ); // ok: calls Derived::f(double)
}

Cheers! --M
 
J

Josefo

Hello:
mlimber said:
This code works for me:

#include <iostream>
#include <exception>
using namespace std;

class myexception : public exception
{
public:
virtual const char* what() const
{
return "My exception happened";
}
};

int main()
{
try
{
throw myexception();
}
catch( const exception& e )
{
cout << e.what() << endl;
}
return 0;
}

But not for me. I get this run-time errors:

josemanuel@josefo:~/C++/C++_Language_Tutorial$ c++
standard_exception_mlimber_good.c
standard_exception_mlimber_good.c:8: error: especificador throw más
flexible para 'virtual const char* myexception::what() const'
/usr/lib/gcc/i486-linux-gnu/4.0.3/../../../../include/c++/4.0.3/exception:61:
error: sustituyendo 'virtual const char* std::exception::what()
const throw ()'


(By the way, trivial spanish-to-english translation:
especificador mas flexible para ...............more flexible specifier
for
substituyendo..................................substituting
)
I am running this versionof the compiler:

josemanuel@josefo:~/C++/C++_Language_Tutorial$ c++ -v
Usando especificaciones internas.
Objetivo: i486-linux-gnu
Configurado con: ../src/configure -v
--enable-languages=c,c++,java,f95,objc,ada,treelang --prefix=/usr
--enable-shared --with-system-zlib --libexecdir=/usr/lib
--without-included-gettext --enable-threads=posix --enable-nls
--program-suffix=-4.0 --enable-__cxa_atexit --enable-clocale=gnu
--enable-libstdcxx-debug --enable-java-awt=gtk-default
--enable-gtk-cairo
--with-java-home=/usr/lib/jvm/java-1.4.2-gcj-4.0-1.4.2.0/jre
--enable-mpfr --disable-werror --with-tune=pentium4
--enable-checking=release i486-linux-gnu
Modelo de hilos: posix
gcc versión 4.0.3 (Ubuntu 4.0.3-1ubuntu5)


(translation:
usando especificaciones internas.......using internal specifications
Configurando...configuring
modelo de hilos....model of threads)



Some hint? Cheers

Josefo
 
M

mlimber

Josefo said:
Hello:


But not for me. I get this run-time errors:

josemanuel@josefo:~/C++/C++_Language_Tutorial$ c++
standard_exception_mlimber_good.c
standard_exception_mlimber_good.c:8: error: especificador throw más
flexible para 'virtual const char* myexception::what() const'
/usr/lib/gcc/i486-linux-gnu/4.0.3/../../../../include/c++/4.0.3/exception:61:
error: sustituyendo 'virtual const char* std::exception::what()
const throw ()'


(By the way, trivial spanish-to-english translation:
especificador mas flexible para ...............more flexible specifier
for
substituyendo..................................substituting
)
I am running this versionof the compiler:

josemanuel@josefo:~/C++/C++_Language_Tutorial$ c++ -v
Usando especificaciones internas.
Objetivo: i486-linux-gnu
Configurado con: ../src/configure -v
--enable-languages=c,c++,java,f95,objc,ada,treelang --prefix=/usr
--enable-shared --with-system-zlib --libexecdir=/usr/lib
--without-included-gettext --enable-threads=posix --enable-nls
--program-suffix=-4.0 --enable-__cxa_atexit --enable-clocale=gnu
--enable-libstdcxx-debug --enable-java-awt=gtk-default
--enable-gtk-cairo
--with-java-home=/usr/lib/jvm/java-1.4.2-gcj-4.0-1.4.2.0/jre
--enable-mpfr --disable-werror --with-tune=pentium4
--enable-checking=release i486-linux-gnu
Modelo de hilos: posix
gcc versión 4.0.3 (Ubuntu 4.0.3-1ubuntu5)


(translation:
usando especificaciones internas.......using internal specifications
Configurando...configuring
modelo de hilos....model of threads)



Some hint? Cheers

Looks like your std::exception::what() has a no-throw specification.
Make your overload read:

virtual const char* what() const throw()
{ ... }

Cheers! --M
 
J

Josefo

mlimber said:
Looks like your std::exception::what() has a no-throw specification.
Make your overload read:

virtual const char* what() const throw()
{ ... }

Cheers! --M

Thanks, you are right. And finally...how may I override the no- throw
specification when the exception is launched directly? (without the
"throw myexception", which prevents me to override the no-throw
specification when declaring the derived class "myexception"). For
instance:

// bad_alloc standard exception
#include <iostream>
#include <exception>
using namespace std;

int main () {
try
{
int* myarray= new int[1000000000];
}
catch (exception& e)
{
cout << "Standard exception: " << e.what() << endl;
}
return 0;
}

I get ( thanks to you, now I undestand why, but I do not know how to
solve it):

josemanuel@josefo:~/C++/C++_Language_Tutorial$ ./a.out
Standard exception: St9bad_alloc


Cheers

Josefo
 
M

mlimber

Josefo said:
Thanks, you are right. And finally...how may I override the no- throw
specification when the exception is launched directly? (without the
"throw myexception", which prevents me to override the no-throw
specification when declaring the derived class "myexception"). For
instance:

I think you mean "indirectly" since in the example below "new"
generates the exception ("directly" would be an explicit throw
statement on your part as in the previous posts).
// bad_alloc standard exception
#include <iostream>
#include <exception>
using namespace std;

int main () {
try
{
int* myarray= new int[1000000000];
}
catch (exception& e)
{
cout << "Standard exception: " << e.what() << endl;
}
return 0;
}

I get ( thanks to you, now I undestand why, but I do not know how to
solve it):

josemanuel@josefo:~/C++/C++_Language_Tutorial$ ./a.out
Standard exception: St9bad_alloc

I don't understand what the problem is. You get a std::bad_alloc
exception, which is just what you should get if new fails. What were
you expecting?

Cheers! --M
 
R

red floyd

Josefo said:
Thanks, you are right. And finally...how may I override the no- throw
specification when the exception is launched directly? (without the
"throw myexception", which prevents me to override the no-throw
specification when declaring the derived class "myexception"). For
instance:

I think you're confused. the no throw specification means that what()
is guaranteed not to throw.
 
J

Jerry Coffin

[ ... ]
I think you're confused. the no throw specification means that what()
is guaranteed not to throw.

Not really. It really means if it throws anything, unexpected() will be
called (and by default, unexpected() will call terminate()). Therefore,
what() can throw, but nothing can catch whatever it throws. The user can
use set_unexpected to change the default behavior, but the unexpected
handler cannot return -- it can only exit by throwing another exception
that is allowed by the original exception specification. Since that list
is empty in this case, you can't do a whole lot else in the unexpected
exception handler either...
 
J

Josefo

mlimber said:
I think you mean "indirectly" since in the example below "new"
generates the exception ("directly" would be an explicit throw
statement on your part as in the previous posts).

You are right. I'm sorry, I was messing the things.
// bad_alloc standard exception
#include <iostream>
#include <exception>
using namespace std;

int main () {
try
{
int* myarray= new int[1000000000];
}
catch (exception& e)
{
cout << "Standard exception: " << e.what() << endl;
}
return 0;
}

I get ( thanks to you, now I undestand why, but I do not know how to
solve it):

josemanuel@josefo:~/C++/C++_Language_Tutorial$ ./a.out
Standard exception: St9bad_alloc

I don't understand what the problem is. You get a std::bad_alloc
exception, which is just what you should get if new fails. What were
you expecting?

Right. Thanks a lot to all of you.

Cheers.

Josefo
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top