Boost logo

Boost :

Subject: Re: [boost] [review] Review of Outcome v2 (Fri-19-Jan to Sun-28-Jan, 2018)
From: Andrey Semashev (andrey.semashev_at_[hidden])
Date: 2018-02-01 11:10:28


On 02/01/18 10:01, Jonathan Müller via Boost wrote:
> On Feb 1, 2018 7:56 AM, "Emil Dotchevski via Boost" <boost_at_[hidden]>
> wrote:
>
> On Wed, Jan 31, 2018 at 10:30 PM, Gavin Lambert via Boost <
> boost_at_[hidden]> wrote:
>
>> On 1/02/2018 19:09, Emil Dotchevski wrote:
>>
>>> The factory method technique also allows somewhat restoring a stronger
>>>> invariant -- only the constructor and destructor need to cope with empty
>>>> or
>>>> otherwise uninitialised instances; other methods can be reasonably
>>>> assured
>>>> that no such instances escaped the factory method.
>>>>
>>>
>>> This is true only if you use exceptions to report errors from the
> factory.
>>> Otherwise it is most definitely NOT reasonable for member functions to
>>> assume that the object has been initialized, because nothing guarantees
>>> that an error reported by the factory wasn't ignored.
>>>
>>
>> The factory itself provides that guarantee. One such pseudo-code
>> implementation might be:
>>
>> static std::unique_ptr<A> A::create(args...) noexcept
>> {
>> // the constructor is itself noexcept and cannot fail
>> std::unique_ptr<A> a(new (std::nothrow) A(arg1));
>> if (!a)
>> return nullptr;
>>
>> if (!a->private_init_stuff(arg2, arg3, ...))
>> return nullptr;
>>
>> return a;
>> }
>>
>
> This does not protect the user at all:
>
> std::unique_ptr<A> a=A::create();
> a->foo(); //undefined behavior
>
> Compare to:
>
> static std::unique_ptr<A> A::create(args...)
> {
> std::unique_ptr<A> a(new A(arg1)); //new throws on error, A::A() throws
> on error
> return a;
> }
>
> And then:
>
> std::unique_ptr<A> a=A::create();
> a->foo(); //Okay, a is guaranteed to be valid.
>
>
>
> Yeah but you can write stupid code with anything:
>
> ```
> std::unique_ptr<A> a;
> try
> {
> a =A::create();
> }
> catch (...) {}
> a->foo(); // ups
> ```

The important difference between using exceptions and error codes (or
Boost.Outcome, I presume) is that in case of exceptions the user has to
make an effort to write broken code and the correct code most of the
time comes naturally, while with manual error checking it is the other
way around. This is the reason why manual error checking is more prone
to mistakes in error handling.

PS: All that, of course, is given that RAII is ubiquitous. If it's not
then error handling is difficult regardless of the tool you use.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk