Boost logo

Boost Users :

Subject: Re: [Boost-users] exception: use of error_info can mask real exceptions
From: Andrew Venikov (andrew.venikov_at_[hidden])
Date: 2009-05-25 03:12:16


Andrew Venikov wrote:

> Unfortunately, it seems that using '<<' syntax it will be impossible to
> catch exceptions. I hate macros as much as the next guy, but it looks
> like this sort of problem is solvable only using macros.

Well, when I said that in my previous post, I spoke too soon.
It looks like there actually may be a way. At least for the simple
cases. The problem currently is that error_info constructor
expects an already constructed object of value_type. The construction
of value_type happens outside of error_info's constructor, so we
can't catch it.
But if we generate error_info in such a way that we would mimic all
value_type's constructors, e.g. generate error_info constructors with
value_type's signatures, then we could do value_type construction
right in error_info constructor body, thus having an ability to catch
all exceptions. If exception happens, then we would make the current
error_info essentially a dud. If not, then we could swap out the local
object with a value_type member of error_info.

To generate these constructors we would use SFINAE with a dummy
construction of value_type using error_info's argument types.

Like this:

template <class Tag, typename value_type>
class error_info
{
     value_type v_;
...
public:

     //Constructor with one argument
     template <typename T>
     error_info(T in,
        int2type<sizeof(new value_type(T()))> * dummy =0)
     {
       try
       {
         value_type temp(in);
         v_.swap(temp);
       }
       catch(...)
       {
          //Mark this object as a "dud"
       }
     }

     //Constructor with two arguments
     template <typename T1, typename T2>
     error_info(T1 in1, T2 in2,
        int2type<sizeof(new value_type(T1(), T2()))> * dummy =0)
     {
       try
       {
         value_type temp(in1, in2);
         v_.swap(temp);
       }
       catch(...)
       {
          //Mark this object as a "dud"
       }
     }

     //And so forth
     ....
};

error_info<struct a_tag, std::string> ErrorDescriptor;
throw AnError() << ErrorDescriptor("abcd"); //Will guarantee
                    //that even if string() throws an exception,
                    //AnError() is propagated.

The above code assumes that value_type has a swap member function. The
code can be changed to use boost::move (or new std::move), but I'm not
yet terribly familiar with those, that's why I didn't use them. I was
just trying to show the concept. All we need to know is that value_type
is movable.

Of course, this will not help us if error_info() is initialized with
initializers that in turn may throw exception (like calling a function).
But I expect those cases to be rare. And in any case, that's in user's
control. But at least we've eliminated a problem that was out of user's
control.

Andy.


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net