Topic: Behavior of ios::exceptions when an exception has already been raised.


Author: James Kanze <james.kanze@gmail.com>
Date: Sun, 15 Jul 2007 18:12:57 CST
Raw View
Consider the following program:

    #include <iostream>
    #include <streambuf>
    #include <cstdlib>

    class MySB : public std::streambuf
    {
    protected:
        int                 overflow( int )
        {
            return EOF ;
        }
    } ;

    class RaiiX
    {
    public:
        RaiiX( std::ios& stream )
            :   myStream( stream )
            ,   myMask( stream.exceptions() )
        {
        }
        ~RaiiX()
        {
            myStream.exceptions( myMask ) ;
        }

    private:
        std::ios&           myStream ;
        std::ios::iostate   myMask ;
    } ;


    void
    f( std::ostream& dest )
    {
        RaiiX               x( dest ) ;
        dest << "Doh!" ;
    }

    int
    main()
    {
        try {
            MySB                sb ;
            std::ostream        out( &sb ) ;
            out.exceptions( std::ios::badbit ) ;
            f( out ) ;
            return EXIT_SUCCESS ;
        } catch ( std::exception const& error ) {
            std::cerr << "Error: " << error.what() << std::endl ;
            return EXIT_FAILURE ;
        }
    }

When compiled with g++, then run, it causes terminate to be called,
because setting the exception mask in the destructor of RaiiX causes
an
exception to be thrown, even when we are unwinding the stack because
of
an exception.  A quick check in the standard shows that this is what
is
actually required.  (Well, actually, it's not clear that this is
required.  The text says:

    Post condition: exception() == except
    Effects: calls clear( rdstate() )

But it doesn't say that the post-condition must be established before
the "effects" clause is executed.  Still, that's the only reasonable
conclusion, because otherwise, the effects clause would have no
effect.)

But is this intentional?  It more or less means that RAII cannot be
used
to save the exception mask.  Shouldn't the behavior of the non-const
basic_ios::exceptions( except ) something along the lines of:

    old = exception() ;
    <i>sets exception mask to except & ~ old</i>
    clear( rdstate() ) ;
    <i>sets exception mask to except</i>

(The above isn't very formalized.  If there is a general agreement
that
this is really what is wanted, I'll try to formulate it better, and
write up a short proposal for the correction.)

--
James Kanze (Gabi Software)            email: james.kanze@gmail.com
Conseils en informatique orient   e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S   mard, 78210 St.-Cyr-l'   cole, France, +33 (0)1 30 23 00 34


---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]