Exception handling problem

W

woodbrian77

I'm not sure if the following is due to a misunderstanding
on my part or a clang 3.2 problem. Notice the two catch
blocks below.

try{
// ...
}catch(eof const& ex){
syslog(LOG_ERR,"Got end of stream notice: %s",ex.what());
// ...
}catch:):std::exception const& ex){
syslog(LOG_ERR,"Problem handling response %s",ex.what());
// ...
}

In a test I've caused my back tier to close it's connection
to the middle tier every 500th request. The code above is
from the middle tier. I have two definitions of the eof
class:

#if 0
class eof : public failure {

public:
explicit eof (char const* what_) : failure(what_)
{}

~eof () throw()
{}
};

#else

class eof : public ::std::exception {
::std::string whatStr;

public:
explicit eof (char const* what_) : whatStr(what_)
{}

~eof () throw()
{}

char const* what () const throw()
{ return whatStr.c_str(); }

template <class T>
eof& operator<< (T val)
{
::std::eek:stringstream ss;
ss << val;
whatStr.append(ss.str().c_str());
return *this;
}
};

#endif

If I use the second, longer form, an eof exception is
caught as expected. But if I build the middle tier with
the shorter form of eof, the handler for std::exception
is the one used. This code and the definition of failure
is here --
http://webEbenezer.net/misc/ErrorWords.hh

I'd prefer to use the shorter form, but can't at this point.
Thanks in advance.


Brian
Ebenezer Enterprises - In G-d we trust.
http://webEbenezer.net
 
I

Ian Collins

I'm not sure if the following is due to a misunderstanding
on my part or a clang 3.2 problem. Notice the two catch
blocks below.
If I use the second, longer form, an eof exception is
caught as expected. But if I build the middle tier with
the shorter form of eof, the handler for std::exception
is the one used. This code and the definition of failure
is here --
http://webEbenezer.net/misc/ErrorWords.hh

I'd prefer to use the shorter form, but can't at this point.
Thanks in advance.

The code looks fine (except for those pesky prepended colons!). Maybe
you have hit a compiler bug. Does the code work as expected with gcc?
 
V

Victor Bazarov

I'm not sure if the following is due to a misunderstanding
on my part or a clang 3.2 problem. Notice the two catch
blocks below.
[...]

You're supposed to catch what's thrown. I didn't see the code that
throws. Did you write it? Or does it come from the system?

V
 
W

woodbrian77

You're supposed to catch what's thrown. I didn't see the code that
throws. Did you write it? Or does it come from the system?

int cmw::sockRead (sock_type sock, void* data, int len
, sockaddr* fromAddr, socklen_t* fromLen)
{
int rc = recvfrom(sock
, static_cast<char*> (data)
, len
, 0
, fromAddr
, fromLen
);
if (rc < 0) {
auto err = GetError();
if (ECONNRESET == err) {
throw eof("sockRead -- ECONNRESET");
}
throw failure("sockRead -- len: ") << len << " errno: " << err;
} else {
if (rc == 0) {
throw eof("sockRead -- rc == 0. len: ") << len; // <-- this line
}
return rc;
}
}

Sorry. The line with the comment throws. I get the
same message/what string/ either way and I've checked
that that message is only thrown in this one place.
 
T

Thomas J. Gritzan

Am 03.07.2013 23:29, schrieb (e-mail address removed):
throw eof("sockRead -- rc == 0. len: ") << len; // <-- this line
Sorry. The line with the comment throws. I get the
same message/what string/ either way and I've checked
that that message is only thrown in this one place.

Throwing together a short example with the same problem:

#include <iostream>

struct failure {
failure& self() {
return *this;
}
};
struct eof : failure {};

int main()
{
try {
throw eof().self();
}
catch (eof const&) {
std::cout << "ok!" << std::endl;
}
catch (...) {
std::cout << "problem!" << std::endl;
}
}

You don't throw an /eof/, you throw a /failure/ because operator<<
returns a failure&. This is called slicing.
 
W

woodbrian77

You don't throw an /eof/, you throw a /failure/ because operator<<
returns a failure&. This is called slicing.

That makes sense.

I tried this:

class eof : public failure {

public:
explicit eof (char const* what_) : failure(what_)
{}

~eof () throw()
{}

template <class T>
eof& operator<< (T val)
{
failure::eek:perator<<(val);
return *this;
}
};

And that is working as expected.
 
J

James Kanze

int cmw::sockRead (sock_type sock, void* data, int len
, sockaddr* fromAddr, socklen_t* fromLen)
{
int rc = recvfrom(sock
, static_cast<char*> (data)
, len
, 0
, fromAddr
, fromLen
);
if (rc < 0) {
auto err = GetError();
if (ECONNRESET == err) {
throw eof("sockRead -- ECONNRESET");
}
throw failure("sockRead -- len: ") << len << " errno: " << err;
} else {
if (rc == 0) {
throw eof("sockRead -- rc == 0. len: ") << len; // <-- this line
}
return rc;
}
}
Sorry. The line with the comment throws. I get the
same message/what string/ either way and I've checked
that that message is only thrown in this one place.

What is the type returned from "eof( ... ) << len"? If the
operator<< is defined in failure, and it returns a failure&,
then what will be thrown is a failure, not an eof. The type
thrown is the *static* type of the expression, by copy (and
thus, with possible slicing). If for some reason, you need to
throw the dynamic type, the solution is to provide a virtual
member function (say raise), and overload that in all of the
derived classes to do the throw there (where the dynamic type
has been resolved). Although in your case, that would lead to
some mighty strange syntax:

(eof( "..." ) << len).raise();

Alternatively, you can use a global function:

raise( eof( "..." ) << len );

which is less awkward.
 
W

woodbrian77

What is the type returned from "eof( ... ) << len"? If the
operator<< is defined in failure, and it returns a failure&,
then what will be thrown is a failure, not an eof. The type
thrown is the *static* type of the expression, by copy (and
thus, with possible slicing).

Yes, that was the problem.
If for some reason, you need to
throw the dynamic type, the solution is to provide a virtual
member function (say raise), and overload that in all of the
derived classes to do the throw there (where the dynamic type
has been resolved). Although in your case, that would lead to
some mighty strange syntax:

(eof( "..." ) << len).raise();

Alternatively, you can use a global function:


raise( eof( "..." ) << len );

which is less awkward.

I'm not sure how that would be better than what I
have now -- see my reply to Thomas Gritzan.
 
Ö

Öö Tiib

I'm not sure how that would be better than what I
have now -- see my reply to Thomas Gritzan.

A reason why a central 'raise' function can be better is debugging. If
exceptions are thrown very rarely then it is rather nice place for a
break point.

A reason why your solution would not pass some reviews is that public
'operator<<' in 'eof' hides public 'operator<<' of base class 'failure'.
That is considered needless complexity by lot of coding standards.
 
W

woodbrian77

A reason why a central 'raise' function can be better is debugging. If
exceptions are thrown very rarely then it is rather nice place for a
break point.

I added a couple of raise functions - one that takes a reference
to failure and another that takes a ref to eof. One downside to
this though is now I get a warning "control may reach end of
non-void function". All raise does is throw, but I guess the
compiler doesn't notice that.

A reason why your solution would not pass some reviews is that public
'operator<<' in 'eof' hides public 'operator<<' of base class 'failure'.
That is considered needless complexity by lot of coding standards.

It seems like there's some complexity with alternatives though too.
 
Ö

Öö Tiib

I added a couple of raise functions - one that takes a reference
to failure and another that takes a ref to eof. One downside to
this though is now I get a warning "control may reach end of
non-void function". All raise does is throw, but I guess the
compiler doesn't notice that.

Usually I arrange my code so that it does not warn on functions
that never return. It simpler because I handle errors first.
It seems like there's some complexity with alternatives though too.

Virtual override or different names are always suggested instead of hidden
public member of base class. However, you can't use different names since
it is operator and you can't make it virtual since it is template. I am
correct so far?

Note that the problem is because of very common need ... string building.
Perhaps you should extract that generic concern from exception.
For example with such a ostringstream wrapper:

struct S
{
std::eek:stringstream stream;

template <typename T>
S& operator << (const T& value)
{
using ::eek:perator <<;
stream << value;
return *this;
}

operator std::string() const
{
return stream.str();
}
};

Usage is like:

throw failure( S("sockRead -- len: ") << len << " errno: " << err );
 

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,961
Messages
2,570,131
Members
46,689
Latest member
liammiller

Latest Threads

Top