diff --git a/doc/optional.html b/doc/optional.html index 5512115..d29bd07 100644 --- a/doc/optional.html +++ b/doc/optional.html @@ -20,6 +20,7 @@ HREF="../../../boost/optional/optional.hpp">boost/optional/optional.hpp>
Consider these functions which should return a value but which might not have a value to return:
-(A) double sqrt( double n ); +(A) double sqrt(double n ); (B) char get_async_input(); (C) point polygon::get_any_point_effectively_inside();There are different approaches to the issue of not having a value to return.
@@ -100,11 +101,12 @@ if ( p.second ) and neither default nor value initialization applies, it is said that the object is uninitialized. Its actual value exist but has an indeterminate inital value (c.f. 8.5.9).
-optional<T>
intends to formalize the notion of initialization/no-initialization +optional<T>
intends to formalize the notion of initialization +(or loack of it) allowing a program to test whether an object has been initialized and stating that access to the value of an uninitialized object is undefined behaviour. That is, when a variable is declared as optional<T> and no initial value is given, - the variable is formally uninitialized. A formally uninitialized optional object has conceptually + the variable is formally uninitialized. A formally uninitialized optional object has conceptually no value at all and this situation can be tested at runtime. It is formally undefined behaviour to try to access the value of an uninitialized optional. An uninitialized optional can be assigned a value, in which case its initialization state changes to initialized. Furthermore, given the formal treatment of initialization states in optional objects, it is even possible to reset an optional to uninitialized. @@ -122,8 +124,8 @@ if ( p.second ) Using the Boost.Variant library, this model can be implemented in terms ofboost::variant<T,nil_t>
.
There is precedence for a discriminated union as a model for an optional value: the - Haskell Maybe builtin type constructor, - thus a discriminated unionT+nil_t
serves as a conceptual foundation. + Haskell Maybe builtin type constructor. +Thus, a discriminated unionT+nil_t
serves as a conceptual foundation.A
variant<T,nil_t>
follows naturally from the traditional idiom of extending the range of possible values adding an additional sentinel value with the special meaning of Nothing. However, this additional Nothing value is largely irrelevant for our purpose @@ -180,33 +182,31 @@ object.Direct Value Construction via copy: To introduce a formally initialized wrapped object whose value is obtained as a copy of some object.
-Deep Copy Construction: To obtain a different yet equivalent wrapped +
Deep Copy Construction: To obtain a new yet equivalent wrapped object.
-Direct Value Assignment (upon initialized): To assign the wrapped object a value obtained -as a copy of some object.
+Direct Value Assignment (upon initialized): To assign a value to the wrapped object.
Direct Value Assignment (upon uninitialized): To initialize the wrapped object with a value obtained as a copy of some object.
-Assignnment (upon initialized): To assign the wrapped object a value obtained as a copy -of another wrapper's object.
+Assignnment (upon initialized): To assign to the wrapped object the value +of another wrapped object.
Assignnment (upon uninitialized): To initialize the wrapped object -with value obtained as a copy -of another wrapper's object.
+with value of another wrapped object.Deep Relational Operations (when supported by the type T): To compare wrapped object values taking into account the presence of uninitialized -operands.
+states.Value access: To unwrap the wrapped object.
Initialization state query: To determine if the object is formally initialized or not.
-Swap: To exchange wrapper's objects. (with whatever exception safety +
Swap: To exchange wrapped objects. (with whatever exception safety guarantiees are provided by T's swap).
De-initialization: To release the wrapped object (if any) and leave @@ -313,7 +313,7 @@ class optional optional () ; - optional ( detail::none_t ) ; + optional ( none_t ) ; optional ( T const& v ) ; @@ -325,7 +325,7 @@ class optional template<class TypedInPlaceFactory> explicit optional ( TypedInPlaceFactory const& f ) ; - optional& operator = ( detail::none_t ) ; + optional& operator = ( none_t ) ; optional& operator = ( T const& v ) ; @@ -427,7 +427,7 @@ assert ( !def ) ;
optional<T>::optional( detail::none_t );+
optional<T>::optional( none_t );
Effect: Constructs an optional uninitialized.
Postconditions: *this is uninitialized.
@@ -436,11 +436,12 @@ assert ( !def ) ;T's default constructor is not called.
The -expressionboost::none
denotes an instance ofboost::detail::none_t
that can be +expressionboost::none
denotes an instance ofboost::none_t
that can be used as the parameter.Example:
+@@ -468,7 +469,7 @@ assert ( *opt == v ) ;#include <boost/none.hpp>optional<T> n(none) ; assert ( !n ) ;
-optional<T&>::optional( T ref )+optional<T&>::optional( T& ref )Effect: Directly-Constructs an optional.
Postconditions: *this is initialized and its value is an @@ -522,12 +523,11 @@ assert ( init2 == init ) ;
+Effect: Copy-Constructs an optional.
Postconditions: If rhs is initialized, *this is initialized -and its value is a copy of the internal wrapper holding the references in rhs; else *this +and its value is another reference to the same object referenced by *rhs; else *this is uninitialized.
Throws: Nothing.
-Notes: If rhs is initialized, the internal wrapper will be -copied and just like true references, both *this and rhs will -referr to the same object (will alias).
+Notes: If rhs is initialized, both *this and *rhs will +refeer to the same object (they alias).
Example:
@@ -615,22 +622,55 @@ assert ( *y == v ) ;optional<T&> uninit ; @@ -542,6 +542,13 @@ assert ( *init == v ) ; optional<T> init2 ( init ) ; assert ( *init2 == v ) ; + +v = 3 ; + +assert ( *init == 3 ) ; +assert ( *init2 == 3 ) ; + +Effect: Assigns the value 'rhs' to an optional.
Postconditions: *this is initialized and its value is a copy of rhs.
-Throws: Whatever T::T( T const& ) throws.
-Notes: If *this was initialized, it is first reset to uninitialized -using T::~T(), then T::T(rhs) is called.
-Exception Safety: Basic: Exceptions can only be thrown during T::T( T const& ); -in that case, *this is left uninitialized. -
+Throws: Whatever T::operator=( T const& ) or T::T(T conbst&) throws.
+Notes: If *this was initialized, T's assignment operator is +used, otherwise, its copy-contructor is used.
+Exception Safety: In the event of an exception, the initialization +state of *this is unchanged and its value unspecified as far as optional +is concerned (it is up to T's operator=()) [If *this is initially +uninitialized and T's copy constructor fails, *this is left +properly uninitialized]
Example:
+T x; +optional<T> def ; optional<T> opt(x) ; T y; +def = y ; +assert ( *def == y ) ; opt = y ; -assert ( *opt == y ) ; -// previous value (copy of 'v') destroyed from within 'opt'. +assert ( *opt == y ) ;+
+ +optional<T&>& optional<T&>::operator= ( T& const& rhs ) ;++@@ -644,21 +684,25 @@ assert ( *opt == y ) ; and its value is a copy of the value of rhs; else *this is uninitialized. -Effect: (Re)binds thee wrapped reference.
+Postconditions: *this is initialized +and it references the same object referenced by rhs.
+Notes: If *this was initialized, is is rebound to the +new object. See here for details on this behaviour.
+Example:
++int a = 1 ; +int b = 2 ; +T& ra = a ; +T& rb = b ; +optional<int&> def ; +optional<int&> opt(ra) ; + +def = rb ; // binds 'def' to 'b' through 'rb' +assert ( *def == b ) ; +*def = a ; // changes the value of 'b' to a copy of the value of 'a' +assert ( b == a ) ; +int c = 3; +int& rc = c ; +opt = rc ; // REBINDS to 'c' through 'rc' +c = 4 ; +assert ( *opt == 4 ) ;Throws: Whatever T::T( T const& ) throws.
-Notes: If *this was initialized, it is first reset to uninitialized -using T::~T(), then T::T( T const& ) is called if rhs is initialized. -
-Exception Safety: Basic: Exceptions can only be thrown during T::T( T const& ); -in that case, *this is left uninitialized. +
Throws: Whatever T::operator( T const&) or T::T( T const& ) throws.
+Notes: If both *this and rhs are initially initialized, +T's assignment operator is used. If *this is initially initialized but +rhs is uinitialized, T's destructor is called. If *this is initially +uninitialized but rhs is initialized, T's copy constructor is called.
+Exception Safety: In the event of an exception, the initialization +state of *this is unchanged and its value unspecified as far as optional +is concerned (it is up to T's operator=()) [If *this is initially +uninitialized and T's copy constructor fails, *this is left +properly uninitialized]
Example:
T v; optional<T> opt(v); -optional<T> uninit ; +optional<T> def ; -opt = uninit ; -assert ( !opt ) ; +opt = def ; +assert ( !def ) ; // previous value (copy of 'v') destroyed from within 'opt'.@@ -667,6 +711,40 @@ assert ( !opt ) ;
+optional<T&> & optional<T&>::operator= ( optional<T&> const& rhs ) ;+++ +Effect: (Re)binds thee wrapped reference.
+Postconditions: If *rhs is initialized, *this is initialized +and it references the same object referenced by *rhs; otherwise, *this +is uninitialized (and references no object).
+Notes: If *this was initialized and so is *rhs, this +is is rebound to the new object. See here for details on this behaviour.
+Example:
+++int a = 1 ; +int b = 2 ; +T& ra = a ; +T& rb = b ; +optional<int&> def ; +optional<int&> ora(ra) ; +optional<int&> orb(rb) ; + +def = orb ; // binds 'def' to 'b' through 'rb' wrapped within 'orb' +assert ( *def == b ) ; +*def = ora ; // changes the value of 'b' to a copy of the value of 'a' +assert ( b == a ) ; +int c = 3; +int& rc = c ; +optional<int&> orc(rc) ; +ora = orc ; // REBINDS ora to 'c' through 'rc' +c = 4 ; +assert ( *ora == 4 ) ; ++
+template<U> optional& optional<T (not a ref)>::operator= ( optional<U> const& rhs ) ;Effect: Assigns another convertible optional to an optional.
@@ -674,14 +752,17 @@ assert ( !opt ) ; and its value is a copy of the value of rhs converted to type T; else *this is uninitialized. -Throws: Whatever T::T( U const& ) throws.
-Notes: If *this was initialized, it is first reset to uninitialized -using T::~T(), then T::T( U const& ) is called if rhs is initialized, -which requires a valid conversion from U to T. -
-Exception Safety: Basic: Exceptions can only be thrown during T::T( U const& ); -in that case, *this is left uninitialized. +
Throws: Whatever T::operator=( U const& ) or T::T( U const& ) throws.
+Notes: If both *this and rhs are initially initialized, +T's assignment operator (from U) is used. If *this is initially initialized but +rhs is uinitialized, T's destructor is called. If *this is initially +uninitialized but rhs is initialized, T's converting constructor (from U) is called.
+Exception Safety: In the event of an exception, the initialization +state of *this is unchanged and its value unspecified as far as optional +is concerned (it is up to T's operator=()) [If *this is initially +uninitialized and T's converting constructor fails, *this is left +properly uninitialized]
Example:
T v; @@ -1118,7 +1199,7 @@ class Fred
Optional references
-This library allow the template parameter T to be of reference type: T&, and +
This library allows the template parameter T to be of reference type: T&, and to some extent, T const&.
However, since references are not real objects some restrictions apply and @@ -1141,6 +1222,85 @@ value, a true real reference is stored so aliasing will ocurr:
than the reference itself. +
+Rebinding semantics for assignment of optional +references
+If you assign to an uninitialized optional<T&> the effect is to bind (for the first time) to the object. +Clearly, there is no other choice.
+int x = 1 ; +int& rx = x ; +optional<int&> ora ; +optional<int&> orb(x) ; +ora = orb ; // now 'ora' is bound to 'x' through 'rx' +*ora = 2 ; // Changes value of 'x' through 'ora' +assert(x==2); ++If you assign to a bare C++ reference, the assignment is forwarded to the +referenced object; it's value changes but the reference is never rebound.
+int a = 1 ; +int& ra = a ; +int b = 2 ; +int& rb = b ; +ra = rb ; // Changes the value of 'a' to 'b' +assert(a==b); +b = 3 ; +assert(ra!=b); // 'ra' is not rebound to 'b' ++Now, if you assign to an initialized optional<T&>, the effect is to +rebind to the new object instead of assigning the referee. This is unlike +bare C++ references.
+int a = 1 ; +int b = 2 ; +int& ra = a ; +int& rb = b ; +optional<int&> ora(ra) ; +optional<int&> orb(rb) ; +ora = orb ; // 'ora' is rebound to 'b' +*ora = 3 ; // Changes value of 'b' (not 'a') +assert(a==1); +assert(b==3); ++Rationale:
+Rebinding semantics for the assignment of initialized optional +references has been choosen to provide consistency among initialization +states even at the expense of lack of consistency with the semantics of bare +C++ references.
+
+It is true that optional<U> strives to behave as much as possible as U does +whenever it is initialized; but in the case when U is T&, doing so would result +in incosistent behaviour w.r.t to the lvalue initialization state.Imagine optional<T&> fordwarding assignment to the referenced object (thus +changing the referenced object value but not rebinding), and consider the +following code :
+optional<int&> a = get(); + int x = 1 ; + int& rx = x ; + optional<int&> b(rx); + a = b ; ++What does the assignment do?
+
+If 'a' is uninitialized, the answer is clear: it binds to 'x' (we now have +another reference to 'x').
+But what if 'a' is already initiliazed? it would change the value of the +referenced object (whatever that is); which is inconsistent with the other +possible case.If optional<T&> would assign just like T& does, you would never be able to +use Optional's assignment without explicitely handling the previous +initialization state unless your code is capable of functioning whether after +the assignment, 'a' +aliases the same object as 'b' or not.
+That is, you would have to discriminate in order to be consistency.
+
+
+If in your code rebinding to another object is not an option, then is very +likely that binding for the fist time isn't either. In such case, assignment to +an uninitialized optional<T&> shall be prohibited. It is quite +possible that in such scenario the precondition that the lvalue must be already +initialized exist. If it doesn't, then binding for the first time is OK while +rebinding is not which is IMO +very unlikely.
+In such scenario, you can assign the value itself directly, as in:assert(!!opt); +*opt=value;+
In-Place Factories
@@ -1152,7 +1312,7 @@ type to be Copy Constructible constructed object, often temporary, just to follow the copy from:struct X { - X ( int, std::string ) ; + X ( int, std:::string ) ; } ;class W { @@ -1222,7 +1382,7 @@ public: { // Wrapped object constructed in-place via a TypedInPlaceFactory. // No temporary created. - W ( TypedInPlaceFactory2<X,int,std::string>(123,"hello")) ; + W ( TypedInPlaceFactory2<X,int,std::string&rt;(123,"hello")) ; }The factories are divided in two groups:
@@ -1303,7 +1463,7 @@ of the assignment methods: InPlaceFactory const& )
- -
template<class TypedInPlaceFactory> optional<T>::operator= ( TypedInPlaceFactory const& )
- +
optional<T>::reset ( T const& )
optional<T>:::reset ( T const&)
Can only guarantee the basic exception safety: The lvalue optional is left uninitialized if an exception is thrown (any previous value is first destroyed using T::~T())
@@ -1320,11 +1480,11 @@ for T::T ( T const& ), you know that optional's assignment and reset has the // Case 1: Exception thrown during assignment. // T v0(123); -optional<T> opt0(v0); +optional<T> opt0(v0); try { T v1(456); - optional<T> opt1(v1); + optional<T> opt1(v1); opt0 = opt1 ; // If no exception was thrown, assignment succeeded. @@ -1340,7 +1500,7 @@ catch(...) // Case 2: Exception thrown during reset(v) // T v0(123); -optional<T> opt(v0); +optional<T> opt(v0); try { T v1(456); @@ -1432,8 +1592,8 @@ T is not required to be LICENSE_1_0.txt or copy at @@ -1443,4 +1603,4 @@ the latest version of this file can be found at www.boost.org, and the boost discussion lists