On Thu, Apr 21, 2016 at 3:05 PM, Eric Rescorla <e...@rtfm.com> wrote:
> The general problem that
> it doesn't alleviate is that failure to check the return value leaves you
> with a reference/pointer to an object in an ill-defined half-constructed
> state. At least for heap allocations, I'd much rather have the property that
> failures leave you with a null pointer.

First of all, with neither approach do you end up with a null pointer,
at least not in Gecko where we have infallible new. So let's ignore
that sentence.

As for the notion of a half-constructed object....

With constructor+Init you have three possible object states in a
well-coded class.

- Half-constructed (i.e. after the constructor runs, but before Init()
is called). The destructor shouldn't need to handle this.

- Fully-constructed (after successful Init()). The destructor needs to
handle this.

- Fully-failed (after failed Init()). The destructor needs to handle this.

With constructor+outparam you have two possible object states in a
well-coded class.

- Fully-constructed (after successful construction). The destructor
needs to handle this.

- Fully-failed (after failed construction). The destructor needs to handle this.

You can still screw up in three ways with either approach.

- If, on failure, you don't appropriately roll back any partial
initialization already done, bad things could happen. E.g. you could
leak resources that you've allocated, or you could leave things in a
state that causes problems for the destructor.

- If your destructor doesn't handle both the fully-constructed case
(unlikely) and the fully-failed case (see the crash in bug 1265035).

- If you forget to check for failure at your call sites.

None of this affects my proposal. All the mistakes you can make with
constructor+outparam have the same or extremely similar mistakes
possible with constructor+Init. But with my proposal you can use
references and |const| in more places, and the code ends up looking
nicer because you do everything in one function instead of two.


> So, if we are going to do something along these lines, I would want it to be
> a convention that if you use MakeUnique and the like (as you should) then
> they automatically validate correct construction and if not return an empty
> pointer.

MakeUnique() just allocates and calls the constructor. If you have
fallible steps in your intialization then MakeUnique() won't help you;
you'll still have either call your Init() function afterwards or check
your nsresult& outparam. So that's not relevant.

Maybe you're referring to factory methods, like this:

  static T* T::New();

which would return null on failure. Such methods can be useful, but
there's two problems. First, they're not applicable to stack-allocated
objects. Second, you still have to do your fallible initialization
*within* the factory method, and so you still have to choose with
either constructor+Init or constructor+outparam, so you still have to
make a choice.

Nick
_______________________________________________
dev-platform mailing list
dev-platform@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-platform

Reply via email to