|
Boost : |
Subject: Re: [boost] Noexcept
From: Andrzej Krzemienski (akrzemi1_at_[hidden])
Date: 2017-06-14 08:57:56
2017-06-14 2:29 GMT+02:00 Emil Dotchevski via Boost <boost_at_[hidden]>:
> On Tue, Jun 13, 2017 at 4:33 PM, Gavin Lambert via Boost <
> boost_at_[hidden]> wrote:
>
> > On 13/06/2017 21:39, Emil Dotchevski wrote:
> >
> >> I can't imagine a function which returns shared_ptr<T> *and* which
> >> could fail, to return an empty one in case of success. That said, in
> >> that case all it means is that you can't use throw_ directly in a return
> >> expression; or you could partially specialize throw_return<> for a
> specific
> >> type of shared_ptr, if that's appropriate.
> >>
> > private:
> > void create_X_if_needed() noexcept
> > {
> > if (!m_X)
> > {
> > try
> > {
> > m_X = make_shared<X>();
> > }
> > catch (internal_error const& e)
> > {
> > throw_(e.code());
> > }
> > }
> > }
> >
> > public:
> > shared_ptr<X> get_X_if_enabled() noexcept
> > {
> > if (feature_X_enabled())
> > {
> > create_X_if_needed();
> > }
> > return m_X;
> > }
> >
> > get_X_if_enabled() could return an empty pointer in two cases:
> >
> > 1. If feature_X_enabled() returns false during all calls, this is a
> > successful return with no pointer.
> > 2. If X's constructor throws an internal_error, this is an error code
> > return with no pointer.
> >
> > Regardless, the correct way to check for errors is to see if the result
> is
> >> valid. This is the price one must pay when not using exception handling.
> >>
> >
> > Isn't the correct way to check for errors (without explicitly catching
> > errors) in this case to call has_current_error()?
> >
>
> Gavin, thank you for this question. Yes, in this case has_current_error()
> would be correct, since the return value itself can't communicate success
> or failure.
>
>
> > Granted in this case get_X_if_enabled doesn't actually need to explicitly
> > check for errors since the following statements will work regardless of
> > whether there was an error state or not.
>
>
> That seems wrong to me. It's difficult to reason about something like this
> in the abstract, but presumably failing to create_X is a Big Problem while
> the feature_X being disabled is not. If I've enabled feature_X, I probably
> don't want it to fail to work silently.
>
>
> > But say if it wanted to do some logging only in the case where
> > create_X_if_needed didn't fail, that would have to be written something
> > like this:
> >
> > shared_ptr<X> get_X_if_enabled() noexcept
> > {
> > if (feature_X_enabled())
> > {
> > create_X_if_needed();
> > if (!has_current_error())
> > {
> > log("has X");
> > }
> > }
> > return m_X;
> > }
> >
> > The other possibility is to catch and rethrow the error, but that seems
> > more cumbersome and error-prone.
> >
>
> I think it's not cumbersome at all. Just like when using exceptions, with
> Noexcept the ability to catch_, do_some_work then throw_ is an important
> feature. Consider that in general in this context you might not have the
> slightest idea what errors may pass through it; so you'd:
>
> if( auto tr=try_(....) ) {
> //ok good, do work then return a "good" value
> } else {
> log(BOOST_DIAGNOSTIC_INFORMATION(*tr.catch_<>()));
> return throw_();
> }
>
> Except it won't work, you've uncovered an omission in the Noexcept API. The
> problem is that catch_<> will flag the error as handled, and in this case
> you don't want that. I need to add another function similar to catch_<>
> which only gets the error without handling it. Not sure what to call it, or
> maybe instead I can add a member function tr.throw_() which flags the error
> as unhandled.
>
Yes. this would make Noexcept superior to C++ exceptions in this aspect:
this would allow to easily identify when you are handling the exception and
when you are just modifying the exception. Call it "augment"?
Regards,
&rzej;
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk