Title
Catching exceptions with ambiguous base classes
Status
nad
Section
14.4 [except.handle]
Submitter
Sergey P. Derevyago

Created on 2001-09-04.00:00:00 last changed 281 months ago

Messages

Date: 2001-10-15.00:00:00

Notes from the 10/01 meeting:

The Core Working Group did not feel this was a significant problem. Catching either of the ambiguous base classes would be surprising, and giving an error on throwing an object that has an ambiguous base class would break existing code.

Date: 2001-09-04.00:00:00

14.4 [except.handle] paragraph 3 contains the following text:

A handler is a match for a throw-expression with an object of type E if
  • The handler is of type cv T or cv T& and E and T are the same type (ignoring the top-level cv- qualifiers), or
  • the handler is of type cv T or cv T& and T is an unambiguous public base class of E, or
  • the handler is of type cv1 T* cv2 and E is a pointer type that can be converted to the type of the handler by either or both of
    • a standard pointer conversion (7.3.12 [conv.ptr]) not involving conversions to pointers to private or protected or ambiguous classes
    • a qualification conversion

I propose to alter this text to allow to catch exceptions with ambiguous public base classes by some of the public subobjects. I'm really sure that if someone writes:

    try {
        // ...
    }
    catch (Matherr& m) {
        // ...
    }
he really wants to catch all Matherrs rather than to allow some of the Matherrs to escape:
    class SomeMatherr : public Matherr { /* */ };
    struct TrickyBase1 : public SomeMatherr { /* */ };
    struct TrickyBase2 : public SomeMatherr { /* */ };
    struct TrickyMatherr : public TrickyBase1, TrickyBase2 { /* */ };

According to the standard TrickyMatherr will leak through the catch (Matherr& m) clause. For example:

    #include <stdio.h>

    struct B {};
    struct B1 : B {};
    struct B2 : B {};
    struct D : B1, B2 {};  // D() has two B() subobjects

    void f() { throw D(); }

    int main()
    {
     try { f(); }
     catch (B& b) { puts("B&"); }  // passed
     catch (D& d) { puts("D&"); }  // really works _after_ B&!!!
    }

Also I see one more possible solution: to forbid objects with ambiguous base classes to be "exceptional objects" (for example Borland C++ goes this way) but it seems to be unnecessary restrictive.

History
Date User Action Args
2001-11-09 00:00:00adminsetmessages: + msg581
2001-11-09 00:00:00adminsetstatus: open -> nad
2001-09-04 00:00:00admincreate