Exception handling problem

Discussion in 'C++' started by woodbrian77@gmail.com, Jul 3, 2013.

  1. Guest

    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
     
    , Jul 3, 2013
    #1
    1. Advertising

  2. Ian Collins Guest

    wrote:
    > 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.
    >

    <snip>
    >
    > 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?

    --
    Ian Collins
     
    Ian Collins, Jul 3, 2013
    #2
    1. Advertising

  3. On 7/3/2013 4:33 PM, wrote:
    > 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
    --
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Jul 3, 2013
    #3
  4. Guest

    On Wednesday, July 3, 2013 8:53:49 PM UTC, Ian Collins wrote:
    >
    > 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?
    >


    Checking. Using gcc 4.8.0 it behaves the same as clang.
    I suppose it's unlikely they are both wrong.

    The makefile is here --
    http://webEbenezer.net/misc/makefile
    ..
     
    , Jul 3, 2013
    #4
  5. Guest

    On Wednesday, July 3, 2013 9:18:30 PM UTC, Victor Bazarov wrote:
    >
    > 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.
     
    , Jul 3, 2013
    #5
  6. Am 03.07.2013 23:29, schrieb :
    > On Wednesday, July 3, 2013 9:18:30 PM UTC, Victor Bazarov wrote:
    >>
    >> 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?
    >>

    >
    > 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.

    --
    Thomas
     
    Thomas J. Gritzan, Jul 3, 2013
    #6
  7. Guest

    On Wednesday, July 3, 2013 10:25:35 PM UTC, Thomas J. Gritzan wrote:

    > 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.
     
    , Jul 3, 2013
    #7
  8. James Kanze Guest

    On Wednesday, July 3, 2013 10:29:43 PM UTC+1, wrote:
    > On Wednesday, July 3, 2013 9:18:30 PM UTC, Victor Bazarov wrote:


    > > 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.


    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.

    --
    James
     
    James Kanze, Jul 4, 2013
    #8
  9. Guest

    On Thursday, July 4, 2013 12:19:04 PM UTC-5, James Kanze wrote:
    >
    > 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.
     
    , Jul 4, 2013
    #9
  10. Öö Tiib Guest

    On Thursday, 4 July 2013 21:42:20 UTC+3, wrote:
    > On Thursday, July 4, 2013 12:19:04 PM UTC-5, James Kanze wrote:
    > > 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.


    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.
     
    Öö Tiib, Jul 4, 2013
    #10
  11. Guest

    On Thursday, July 4, 2013 9:39:26 PM UTC, Öö Tiib wrote:
    >
    > 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.
     
    , Jul 6, 2013
    #11
  12. Öö Tiib Guest

    On Sunday, 7 July 2013 00:49:18 UTC+3, wrote:
    > On Thursday, July 4, 2013 9:39:26 PM UTC, Öö Tiib wrote:
    > > 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.


    Usually I arrange my code so that it does not warn on functions
    that never return. It simpler because I handle errors first.

    > > 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.


    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 );
     
    Öö Tiib, Jul 7, 2013
    #12
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Alex

    Exception handling problem

    Alex, Jul 17, 2003, in forum: ASP .Net
    Replies:
    0
    Views:
    335
  2. zcraven

    exception handling problem

    zcraven, Oct 27, 2004, in forum: Java
    Replies:
    11
    Views:
    564
    zcraven
    Oct 29, 2004
  3. Replies:
    5
    Views:
    383
    Kristo
    Apr 6, 2005
  4. Peter
    Replies:
    34
    Views:
    1,942
    James Kanze
    Oct 17, 2009
  5. VSK
    Replies:
    0
    Views:
    249
Loading...

Share This Page