Boost logo

Boost :

From: Fernando Cacciola (fcacciola_at_[hidden])
Date: 2001-08-29 14:32:33


----- Original Message -----
From: Vesa Karvonen <vesa.karvonen_at_[hidden]>
To: <boost_at_[hidden]>
Sent: Wednesday, August 29, 2001 3:06 PM
Subject: Re: [boost] Re: Proposal: statefull objects

> From: "Rainer Deyke" <root_at_[hidden]>
> > It seems to me that 'optional<T>' is in many ways similar to
> > 'scoped_ptr<T>':
> >
> > - Both are either null or contain a single object of type 'T'.
> > - Both are conceptually pointers to the contained object.
> >
> > Differences:
> >
> > - 'scoped_ptr<T>' can contain an object of a derived type;
'optional<T>'
> > cannot.
> > - 'scoped_ptr<T>' keeps the contained object on the heap; 'optional<T>'
> > keeps it stores it directly.
> > - 'scoped_ptr<T>' is initialized with an object that is already created
on
> > the heap. This does not make sense for 'optional<T>'.
>
> There are a couple of major difference that you omitted:
> - 'scoped_ptr<>' objects can not be returned from a function; 'optional<>'
> can.
> - 'scoped_ptr<>' objects can not be copied; 'optional<>' can.
>
> > Given those similarities, I think it makes sense for the interface of
> > 'optional<T>' to resemble the interface of 'scoped_ptr<T>' as closely as
> > possible. If a user of 'optional<T>' later needs to be able to contain
> > objects of derived types, switching to 'scoped_ptr<T>' should take a
minimal
> > amount of effort. The same applies when a user of 'scoped_ptr<T>' who
does
> > not need to contain objects of derived types and wants the greater
> > performance of 'optional<T>'.
>
> Under the current design of scoped_ptr<>, I do not find it likely that a
user
> would convert a design from optional<> to scoped_ptr<> or vice versa.
However,
> shared_ptr<> is another story. See the following table:
>
> | morphology | semantic
> -------------+-------------+---------------
> optional<> | monomorphic | value
> shared_ptr<> | polymorphic | reference
>
>
I think that ANY smart pointer is intended to solve a different problem.
Notice in particular, that with these smart pointers you are required to
create the object before wrapping it. Thus, I don't think that it will ever
be the case that optional<> and some smart ptr be interchanged.

> My impression could be wrong, but it seems to me that optional<> is mostly
> intended for returning values from a function. However, I think that
> optional<> is also useful for other things. In particular, it could be
useful
> for optimization or simplification of optimized logic, because it allows
> omitting potentially expensive initialization of an object.
>
> optional<expensive> x;
>
> ... logic which may initialize x or not ...
>
> if (x)
> {
> ... logic which depends on x ...
> }
>
> I think that I have seen the above kind of pattern many times in my
coding,
> although I believe I have often refactored the code to avoid the pattern.
> Basically, optional<> seems like an intentional and type safe way to say
that
> something may not be needed and may be left uninitialized. Of course, in
many
> cases, it may be possible to simplify the logic in some other way,
avoiding
> the need for optional<>.
>
You have caught the spirit of optional<> quite well!

I originally designed it to solve the "return value or tell me you couldn't"
idiom consistently.
Latter I realized that it could be used to help with a program logic that
deals with values that are left unassigned.
Typically, a small loop that searches for something but just didn't find it,
which I like to implement not as separate function. A data member that
starts uninitialized. Even an optional argument for which I cannot give a
'default' value since there isn't any such value.

Originally, optional required T::T() (and used a separated boolean flag).
Even though it constructed a default T value in its own default constructor,
it was useful in all the cases above when T were a built-in type or small
POD.

If the type of the value that might be uninitialized is *big*, one typically
uses a pointer -or smart pointer- which is simply left as NULL if the value
isn't assigned. This is a fairly common idiom, and this is why I redesigned
optional<> to use pointer sematics.

Eventually, I tried to remove the default construction of T, for which I
found a broken solution (but I'm still on it)

I notice that there is a fundamental difference in the usability of
optional<> if I don't succeed in removing the default-constructible
requierment as it is the current intention.
If I manage to portably let:
  optional<T> def ;
actually bypass T's default constructor -without a heap allocation-, then
this class is more than just a way to make a program a bit easier to write
and read; it is a true performance optimimization, since you could do
something like:

 vector< optional<Fred> > v(10000);

and completely bypass the 10000 calls to Fred::Fred() .

Of course, there have always been ways to solve all this problems.
I just found out that optional<> is very convenient, even if it uses T::T(),
and even more if it bypasses T::T().

Fernando Cacciola
Sierra s.r.l.
fcacciola_at_[hidden]
www.gosierra.com


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