diff --git a/doc/html/boost_optional/dependencies_and_portability.html b/doc/html/boost_optional/dependencies_and_portability.html index a4545e5..20e692b 100644 --- a/doc/html/boost_optional/dependencies_and_portability.html +++ b/doc/html/boost_optional/dependencies_and_portability.html @@ -6,7 +6,7 @@ - + @@ -20,7 +20,7 @@
-PrevUpHomeNext +PrevUpHomeNext

@@ -42,7 +42,7 @@
-PrevUpHomeNext +PrevUpHomeNext
diff --git a/doc/html/boost_optional/detailed_semantics.html b/doc/html/boost_optional/detailed_semantics.html index 9b01adf..8ba71b2 100644 --- a/doc/html/boost_optional/detailed_semantics.html +++ b/doc/html/boost_optional/detailed_semantics.html @@ -629,6 +629,22 @@

+

+ space +

+

+ optional& + optional<T>::operator= ( none_t ) noexcept; +

+
    +
  • + Effect: If *this is initialized destroys its contained + value. +
  • +
  • + Postconditions: *this is uninitialized. +
  • +

space

@@ -1122,7 +1138,7 @@ space

- void optional<T>::reset() ; + void optional<T>::reset() noexcept ;

  • Deprecated: Same as operator=( detail::none_t ); diff --git a/doc/html/boost_optional/development.html b/doc/html/boost_optional/development.html index 09a89e4..f289a04 100644 --- a/doc/html/boost_optional/development.html +++ b/doc/html/boost_optional/development.html @@ -6,7 +6,7 @@ - + @@ -20,7 +20,7 @@
    -PrevUpHomeNext +PrevUpHomeNext

    @@ -407,7 +407,7 @@
    -PrevUpHomeNext +PrevUpHomeNext
    diff --git a/doc/html/boost_optional/exception_safety_guarantees.html b/doc/html/boost_optional/exception_safety_guarantees.html index d95e749..eb29f92 100644 --- a/doc/html/boost_optional/exception_safety_guarantees.html +++ b/doc/html/boost_optional/exception_safety_guarantees.html @@ -28,8 +28,36 @@ Guarantees

    - Because of the current implementation (see Implementation - Notes), all of the assignment methods: + This library assumes that T's + destructor does not throw exceptions. If it does, the behaviour of many operations + on optional<T> is + undefined. +

    +

    + The following mutating operations never throw exceptions: +

    +
      +
    • + optional<T>::operator= ( none_t ) noexcept +
    • +
    • + optional<T>::reset() noexcept +
    • +
    +

    + In addition, the following constructors and the destructor never throw exceptions: +

    +
      +
    • + optional<T>::optional() + noexcept +
    • +
    • + optional<T>::optional( none_t ) noexcept +
    • +
    +

    + Regarding the following assignment functions:

    • @@ -52,88 +80,71 @@ )
    • - 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()) + They forward calls to the corresponding T's + constructors or assignments (depending on whether the optional object is initialized + or not); so if both T's constructor + and the assignment provide strong exception safety guarantee, optional<T>'s assignment + also provides strong exception safety guarantee; otherwise we only get the + basic guarantee. Additionally, if both involved T's + constructor and the assignment never throw, optional<T>'s + assignment also never throws.

    - On the other hand, the uninitializing methods: + Unless T's constructor or assignment + throws, optional<T> does + not throw anything else on its own. A throw during assignment never changes + the initialization state of any optional object involved:

    -
      -
    • - optional<T>::operator= ( detail::none_t ) -
    • -
    • - optional<T>::reset() -
    • -
    -

    - Provide the no-throw guarantee (assuming a no-throw T::~T()) -

    -

    - However, since optional<> - itself doesn't throw any exceptions, the only source for exceptions here are - T's constructor, so if you - know the exception guarantees for T::T ( - T const& ), you - know that optional's assignment - and reset has the same guarantees. -

    -
    //
    -// Case 1: Exception thrown during assignment.
    -//
    -T v0(123);
    -optional<T> opt0(v0);
    +
    optional<T> opt1(val1);
    +optional<T> opt2(val2);
    +assert(opt1);
    +assert(opt2);
    +
     try
     {
    -    T v1(456);
    -    optional<T> opt1(v1);
    -    opt0 = opt1 ;
    -
    -    // If no exception was thrown, assignment succeeded.
    -    assert( *opt0 == v1 ) ;
    +  opt1 = opt2; // throws
     }
     catch(...)
     {
    -    // If any exception was thrown, 'opt0' is reset to uninitialized.
    -    assert( !opt0 ) ;
    -}
    -
    -//
    -// Case 2: Exception thrown during reset(v)
    -//
    -T v0(123);
    -optional<T> opt(v0);
    -try
    -{
    -    T v1(456);
    -    opt.reset ( v1 ) ;
    -
    -    // If no exception was thrown, reset succeeded.
    -    assert( *opt == v1 ) ;
    -}
    -catch(...)
    -{
    -    // If any exception was thrown, 'opt' is reset to uninitialized.
    -    assert( !opt ) ;
    +  assert(opt1);
    +  assert(opt2);
     }
     
    +

    + This also applies to move assignments/constructors. However, move operations + are made no-throw more often. +

    Swap

    - void swap( optional<T>&, - optional<T>& ) has the same exception guarantee as swap(T&,T&) - when both optionals are initialized. If only one of the optionals is initialized, - it gives the same basic exception guarantee as optional<T>::reset( T const& ) (since - optional<T>::reset() doesn't throw). If none of the optionals - is initialized, it has no-throw guarantee since it is a no-op. + Unless swap on optional is + customized, its primary implementation forwards calls to T's + swap or move constructor (depending + on the initialization state of the optional objects). Thus, if both T's swap + and move constructor never throw, swap + on optional<T> never + throws. similarly, if both T's + swap and move constructor offer + strong guarantee, swap on + optional<T> also + offers a strong guarantee. +

    +

    + In case swap on optional is + customized, the call to T's + move constructor are replaced with the calls to T's + default constructor followed by swap. + (This is more useful on older compilers that do not support move semantics, + when one wants to acheive stronger exception safety guarantees.) In this case + the exception safety guarantees for swap + are reliant on the guarantees of T's + swap and default constructor

    diff --git a/doc/html/boost_optional/implementation_notes.html b/doc/html/boost_optional/implementation_notes.html index 626e7f2..48d476c 100644 --- a/doc/html/boost_optional/implementation_notes.html +++ b/doc/html/boost_optional/implementation_notes.html @@ -31,12 +31,12 @@ currently implemented using a custom aligned storage facility built from alignment_of and type_with_alignment (both from Type Traits). It uses a separate boolean flag to indicate the initialization state. Placement new with T's - copy constructor and T's destructor - are explicitly used to initialize,copy and destroy optional values. As a result, - T's default constructor is - effectively by-passed, but the exception guarantees are basic. It is planned - to replace the current implementation with another with stronger exception - safety, such as a future boost::variant. + copy/move constructor and T's + destructor are explicitly used to initialize, copy, move and destroy optional + values. As a result, T's default + constructor is effectively by-passed, but the exception guarantees are basic. + It is planned to replace the current implementation with another with stronger + exception safety, such as a future boost::variant.

    diff --git a/doc/html/boost_optional/motivation.html b/doc/html/boost_optional/motivation.html new file mode 100644 index 0000000..ee00899 --- /dev/null +++ b/doc/html/boost_optional/motivation.html @@ -0,0 +1,128 @@ + + + +Motivation + + + + + + + + +
    + + + + + + +
    Boost C++ LibrariesHomeLibrariesPeopleFAQMore
    +
    +
    +PrevUpHomeNext +
    +
    + +

    + Consider these functions which should return a value but which might not have + a value to return: +

    +
      +
    • + (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. +

    +

    + A typical approach is to consider the existence of a valid return value as + a postcondition, so that if the function cannot compute the value to return, + it has either undefined behavior (and can use assert in a debug build) or uses + a runtime check and throws an exception if the postcondition is violated. This + is a reasonable choice for example, for function (A), because the lack of a + proper return value is directly related to an invalid parameter (out of domain + argument), so it is appropriate to require the callee to supply only parameters + in a valid domain for execution to continue normally. +

    +

    + However, function (B), because of its asynchronous nature, does not fail just + because it can't find a value to return; so it is incorrect to consider such + a situation an error and assert or throw an exception. This function must return, + and somehow, must tell the callee that it is not returning a meaningful value. +

    +

    + A similar situation occurs with function (C): it is conceptually an error to + ask a null-area polygon to return a point inside itself, + but in many applications, it is just impractical for performance reasons to + treat this as an error (because detecting that the polygon has no area might + be too expensive to be required to be tested previously), and either an arbitrary + point (typically at infinity) is returned, or some efficient way to tell the + callee that there is no such point is used. +

    +

    + There are various mechanisms to let functions communicate that the returned + value is not valid. One such mechanism, which is quite common since it has + zero or negligible overhead, is to use a special value which is reserved to + communicate this. Classical examples of such special values are EOF, string::npos, points + at infinity, etc... +

    +

    + When those values exist, i.e. the return type can hold all meaningful values + plus the signal value, this mechanism + is quite appropriate and well known. Unfortunately, there are cases when such + values do not exist. In these cases, the usual alternative is either to use + a wider type, such as int in place + of char; or a compound type, such + as std::pair<point,bool>. +

    +

    + Returning a std::pair<T,bool>, thus attaching a boolean flag to the result + which indicates if the result is meaningful, has the advantage that can be + turned into a consistent idiom since the first element of the pair can be whatever + the function would conceptually return. For example, the last two functions + could have the following interface: +

    +
    std::pair<char,bool> get_async_input();
    +std::pair<point,bool> polygon::get_any_point_effectively_inside();
    +
    +

    + These functions use a consistent interface for dealing with possibly nonexistent + results: +

    +
    std::pair<point,bool> p = poly.get_any_point_effectively_inside();
    +if ( p.second )
    +    flood_fill(p.first);
    +
    +

    + However, not only is this quite a burden syntactically, it is also error prone + since the user can easily use the function result (first element of the pair) + without ever checking if it has a valid value. +

    +

    + Clearly, we need a better idiom. +

    +
    + + + +
    +
    +
    +PrevUpHomeNext +
    + + diff --git a/doc/html/boost_optional/optional_references.html b/doc/html/boost_optional/optional_references.html index fc0f684..e7e325e 100644 --- a/doc/html/boost_optional/optional_references.html +++ b/doc/html/boost_optional/optional_references.html @@ -60,7 +60,7 @@
    • Copies of optional<T&> - will copy the references but all these references will nonetheless reefer + will copy the references but all these references will nonetheless refer to the same object.
    • @@ -68,6 +68,21 @@ than the reference itself.
    +
    + + + + + +
    [Warning]Warning

    + On compilers that do not conform to Standard C++ rules of reference binding, + operations on optional references might give adverse results: rather than + binding a reference to a designated object they may create a temporary and + bind to it. Compilers known to have these deficiencies include GCC versions + 4.2, 4.3, 4.4, 4.5; QCC 4.4.2; MSVC versions 8.0, 9.0, 10.0, 11.0, 12.0. + On these compilers prefer using direct-initialization and copy assignment + of optional references to copy-initialization and assignment from T&. +

    Rvalue diff --git a/doc/html/boost_optional/synopsis.html b/doc/html/boost_optional/synopsis.html index 3963d42..075bfbf 100644 --- a/doc/html/boost_optional/synopsis.html +++ b/doc/html/boost_optional/synopsis.html @@ -60,7 +60,7 @@ template<class TypedInPlaceFactory> explicit optional ( TypedInPlaceFactory const& f ) ; R - optional& operator = ( none_t ) ; + optional& operator = ( none_t ) noexcept ; R optional& operator = ( T const& v ) ; R @@ -100,7 +100,7 @@ // deprecated methods // (deprecated) - void reset() ; R + void reset() noexcept ; R // (deprecated) void reset ( T const& ) ; R diff --git a/doc/html/boost_optional/type_requirements.html b/doc/html/boost_optional/type_requirements.html index 5080e8d..6c68e88 100644 --- a/doc/html/boost_optional/type_requirements.html +++ b/doc/html/boost_optional/type_requirements.html @@ -7,7 +7,7 @@ - + @@ -20,7 +20,7 @@

    -PrevUpHomeNext +PrevUpHomeNext

    @@ -47,7 +47,7 @@
    -PrevUpHomeNext +PrevUpHomeNext
    diff --git a/doc/html/index.html b/doc/html/index.html index b52777d..a39d80f 100644 --- a/doc/html/index.html +++ b/doc/html/index.html @@ -5,7 +5,7 @@ - + @@ -17,7 +17,7 @@
    More

    -
    Next
    +
    Next

    @@ -37,7 +37,8 @@

    - Consider these functions which should return a value but which might not have - a value to return: + This library can be used to represent 'optional' (or 'nullable') objects and + safely pass them by value:

    -
      -
    • - (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. -

    -

    - A typical approach is to consider the existence of a valid return value as - a postcondition, so that if the function cannot compute the value to return, - it has either undefined behavior (and can use assert in a debug build) or uses - a runtime check and throws an exception if the postcondition is violated. This - is a reasonable choice for example, for function (A), because the lack of a - proper return value is directly related to an invalid parameter (out of domain - argument), so it is appropriate to require the callee to supply only parameters - in a valid domain for execution to continue normally. -

    -

    - However, function (B), because of its asynchronous nature, does not fail just - because it can't find a value to return; so it is incorrect to consider such - a situation an error and assert or throw an exception. This function must return, - and somehow, must tell the callee that it is not returning a meaningful value. -

    -

    - A similar situation occurs with function (C): it is conceptually an error to - ask a null-area polygon to return a point inside itself, - but in many applications, it is just impractical for performance reasons to - treat this as an error (because detecting that the polygon has no area might - be too expensive to be required to be tested previously), and either an arbitrary - point (typically at infinity) is returned, or some efficient way to tell the - callee that there is no such point is used. -

    -

    - There are various mechanisms to let functions communicate that the returned - value is not valid. One such mechanism, which is quite common since it has - zero or negligible overhead, is to use a special value which is reserved to - communicate this. Classical examples of such special values are EOF, string::npos, points - at infinity, etc... -

    -

    - When those values exist, i.e. the return type can hold all meaningful values - plus the signal value, this mechanism - is quite appropriate and well known. Unfortunately, there are cases when such - values do not exist. In these cases, the usual alternative is either to use - a wider type, such as int in place - of char; or a compound type, such - as std::pair<point,bool>. -

    -

    - Returning a std::pair<T,bool>, thus attaching a boolean flag to the result - which indicates if the result is meaningful, has the advantage that can be - turned into a consistent idiom since the first element of the pair can be whatever - the function would conceptually return. For example, the last two functions - could have the following interface: -

    -
    std::pair<char,bool> get_async_input();
    -std::pair<point,bool> polygon::get_any_point_effectively_inside();
    +
    optional<int> readInt(); // this function may return either an int or a not-an-int
    +
    +if (optional<int> oi = readInt()) // did I get a real int
    +  cout << "my int is: " << *oi;   // use my int
    +else
    +  cout << "I have no int";
     
    -

    - These functions use a consistent interface for dealing with possibly nonexistent - results: -

    -
    std::pair<point,bool> p = poly.get_any_point_effectively_inside();
    -if ( p.second )
    -    flood_fill(p.first);
    -
    -

    - However, not only is this quite a burden syntactically, it is also error prone - since the user can easily use the function result (first element of the pair) - without ever checking if it has a valid value. -

    -

    - Clearly, we need a better idiom. -

    - +

    Last revised: May 05, 2014 at 07:44:56 GMT

    Last revised: May 07, 2014 at 15:05:52 GMT


    -
    Next
    +
    Next
    diff --git a/doc/implementation_notes.qbk b/doc/implementation_notes.qbk deleted file mode 100644 index 53e6138..0000000 --- a/doc/implementation_notes.qbk +++ /dev/null @@ -1,26 +0,0 @@ -[/ - Boost.Optional - - Copyright (c) 2003-2007 Fernando Luis Cacciola Carballal - - Distributed under the Boost Software License, Version 1.0. - (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt) -] - - - -[section Implementation Notes] - -`optional` is currently implemented using a custom aligned storage facility -built from `alignment_of` and `type_with_alignment` (both from Type Traits). It -uses a separate boolean flag to indicate the initialization state. -Placement new with `T`'s copy constructor and `T`'s destructor are explicitly used -to initialize,copy and destroy optional values. -As a result, `T`'s default constructor is effectively by-passed, but the exception -guarantees are basic. -It is planned to replace the current implementation with another with stronger -exception safety, such as a future `boost::variant`. - -[endsect] - diff --git a/doc/motivation.qbk b/doc/motivation.qbk new file mode 100644 index 0000000..fc014c3 --- /dev/null +++ b/doc/motivation.qbk @@ -0,0 +1,80 @@ +[/ + Boost.Optional + + Copyright (c) 2003-2007 Fernando Luis Cacciola Carballal + Copyright (c) 2014 Andrzej Krzemienski + + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) +] + +[section Motivation] + +Consider these functions which should return a value but which might not have +a value to return: + +* (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. + +A typical approach is to consider the existence of a valid return value as a +postcondition, so that if the function cannot compute the value to return, it +has either undefined behavior (and can use assert in a debug build) or uses a +runtime check and throws an exception if the postcondition is violated. This +is a reasonable choice for example, for function (A), because the lack of a +proper return value is directly related to an invalid parameter (out of domain +argument), so it is appropriate to require the callee to supply only parameters +in a valid domain for execution to continue normally. + +However, function (B), because of its asynchronous nature, does not fail just +because it can't find a value to return; so it is incorrect to consider such +a situation an error and assert or throw an exception. This function must +return, and somehow, must tell the callee that it is not returning a meaningful +value. + +A similar situation occurs with function (C): it is conceptually an error to +ask a ['null-area] polygon to return a point inside itself, but in many +applications, it is just impractical for performance reasons to treat this as +an error (because detecting that the polygon has no area might be too expensive +to be required to be tested previously), and either an arbitrary point +(typically at infinity) is returned, or some efficient way to tell the callee +that there is no such point is used. + +There are various mechanisms to let functions communicate that the returned +value is not valid. One such mechanism, which is quite common since it has +zero or negligible overhead, is to use a special value which is reserved to +communicate this. Classical examples of such special values are `EOF`, +`string::npos`, points at infinity, etc... + +When those values exist, i.e. the return type can hold all meaningful values +['plus] the ['signal] value, this mechanism is quite appropriate and well known. +Unfortunately, there are cases when such values do not exist. In these cases, +the usual alternative is either to use a wider type, such as `int` in place of +`char`; or a compound type, such as `std::pair`. + +Returning a `std::pair`, thus attaching a boolean flag to the result +which indicates if the result is meaningful, has the advantage that can be +turned into a consistent idiom since the first element of the pair can be +whatever the function would conceptually return. For example, the last two +functions could have the following interface: + + std::pair get_async_input(); + std::pair polygon::get_any_point_effectively_inside(); + +These functions use a consistent interface for dealing with possibly nonexistent +results: + + std::pair p = poly.get_any_point_effectively_inside(); + if ( p.second ) + flood_fill(p.first); + +However, not only is this quite a burden syntactically, it is also error prone +since the user can easily use the function result (first element of the pair) +without ever checking if it has a valid value. + +Clearly, we need a better idiom. + +[endsect] \ No newline at end of file diff --git a/doc/optional.qbk b/doc/optional.qbk index d5608be..b81f958 100644 --- a/doc/optional.qbk +++ b/doc/optional.qbk @@ -45,82 +45,23 @@ Distributed under the Boost Software License, Version 1.0. [def __GO_TO__ [$images/callouts/R.png]] -[section Motivation] +[section Introduction] +This library can be used to represent 'optional' (or 'nullable') objects and safely pass them by value: -Consider these functions which should return a value but which might not have -a value to return: - -* (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. - -A typical approach is to consider the existence of a valid return value as a -postcondition, so that if the function cannot compute the value to return, it -has either undefined behavior (and can use assert in a debug build) or uses a -runtime check and throws an exception if the postcondition is violated. This -is a reasonable choice for example, for function (A), because the lack of a -proper return value is directly related to an invalid parameter (out of domain -argument), so it is appropriate to require the callee to supply only parameters -in a valid domain for execution to continue normally. - -However, function (B), because of its asynchronous nature, does not fail just -because it can't find a value to return; so it is incorrect to consider such -a situation an error and assert or throw an exception. This function must -return, and somehow, must tell the callee that it is not returning a meaningful -value. - -A similar situation occurs with function (C): it is conceptually an error to -ask a ['null-area] polygon to return a point inside itself, but in many -applications, it is just impractical for performance reasons to treat this as -an error (because detecting that the polygon has no area might be too expensive -to be required to be tested previously), and either an arbitrary point -(typically at infinity) is returned, or some efficient way to tell the callee -that there is no such point is used. - -There are various mechanisms to let functions communicate that the returned -value is not valid. One such mechanism, which is quite common since it has -zero or negligible overhead, is to use a special value which is reserved to -communicate this. Classical examples of such special values are `EOF`, -`string::npos`, points at infinity, etc... - -When those values exist, i.e. the return type can hold all meaningful values -['plus] the ['signal] value, this mechanism is quite appropriate and well known. -Unfortunately, there are cases when such values do not exist. In these cases, -the usual alternative is either to use a wider type, such as `int` in place of -`char`; or a compound type, such as `std::pair`. - -Returning a `std::pair`, thus attaching a boolean flag to the result -which indicates if the result is meaningful, has the advantage that can be -turned into a consistent idiom since the first element of the pair can be -whatever the function would conceptually return. For example, the last two -functions could have the following interface: - - std::pair get_async_input(); - std::pair polygon::get_any_point_effectively_inside(); - -These functions use a consistent interface for dealing with possibly nonexistent -results: - - std::pair p = poly.get_any_point_effectively_inside(); - if ( p.second ) - flood_fill(p.first); - -However, not only is this quite a burden syntactically, it is also error prone -since the user can easily use the function result (first element of the pair) -without ever checking if it has a valid value. - -Clearly, we need a better idiom. + optional readInt(); // this function may return either an int or a not-an-int + if (optional oi = readInt()) // did I get a real int + cout << "my int is: " << *oi; // use my int + else + cout << "I have no int"; + [endsect] - +[include motivation.qbk] [include development.qbk] [include reference.qbk] [include examples.qbk] [include special_cases.qbk] -[include implementation_notes.qbk] [include dependencies.qbk] [include acknowledgments.qbk] diff --git a/doc/reference.qbk b/doc/reference.qbk index 7ea348d..1c9a6bb 100644 --- a/doc/reference.qbk +++ b/doc/reference.qbk @@ -45,7 +45,7 @@ template explicit optional ( TypedInPlaceFactory const& f ) ; ``[link reference_optional_constructor_factory __GO_TO__]`` - optional& operator = ( none_t ) ; ``[/[link reference_optional_operator_equal_none_t __GO_TO__]]`` + optional& operator = ( none_t ) noexcept ; ``[link reference_optional_operator_equal_none_t __GO_TO__]`` optional& operator = ( T const& v ) ; ``[link reference_optional_operator_equal_value __GO_TO__]`` @@ -85,7 +85,7 @@ // deprecated methods // (deprecated) - void reset() ; ``[link reference_optional_reset __GO_TO__]`` + void reset() noexcept ; ``[link reference_optional_reset __GO_TO__]`` // (deprecated) void reset ( T const& ) ; ``[link reference_optional_reset_value __GO_TO__]`` @@ -483,6 +483,15 @@ assert ( *y == v ) ; __SPACE__ +[#reference_optional_operator_equal_none_t] + +[: `optional& optional::operator= ( none_t ) noexcept;`] + +* [*Effect:] If `*this` is initialized destroys its contained value. +* [*Postconditions: ] `*this` is uninitialized. + +__SPACE__ + [#reference_optional_operator_equal_value] [: `optional& optional::operator= ( T const& rhs ) ;`] @@ -762,7 +771,7 @@ __SPACE__ [#reference_optional_reset] -[: `void optional::reset() ;`] +[: `void optional::reset() noexcept ;`] * [*Deprecated:] Same as `operator=( detail::none_t );` __SPACE__ diff --git a/doc/special_cases.qbk b/doc/special_cases.qbk index 0d7227c..145209d 100644 --- a/doc/special_cases.qbk +++ b/doc/special_cases.qbk @@ -17,10 +17,12 @@ Also, even though `optional` treats it wrapped pseudo-object much as a real value, a true real reference is stored so aliasing will ocurr: * Copies of `optional` will copy the references but all these references -will nonetheless reefer to the same object. +will nonetheless refer to the same object. * Value-access will actually provide access to the referenced object rather than the reference itself. +[warning On compilers that do not conform to Standard C++ rules of reference binding, operations on optional references might give adverse results: rather than binding a reference to a designated object they may create a temporary and bind to it. Compilers known to have these deficiencies include GCC versions 4.2, 4.3, 4.4, 4.5; QCC 4.4.2; MSVC versions 8.0, 9.0, 10.0, 11.0, 12.0. On these compilers prefer using direct-initialization and copy assignment of optional references to copy-initialization and assignment from `T&`.] + [heading Rvalue references] Rvalue references and lvalue references to const have the ability in C++ to extend the life time of a temporary they bind to. Optional references do not have this capability, therefore to avoid surprising effects it is not possible to initialize an optional references from a temporary. Optional rvalue references are disabled altogether. Also, the initialization and assignment of an optional reference to const from rvalue reference is disabled. @@ -291,80 +293,55 @@ instead, it won't compile). [section Exception Safety Guarantees] -Because of the current implementation (see [link boost_optional.implementation_notes Implementation Notes]), all of the assignment methods: +This library assumes that `T`'s destructor does not throw exceptions. If it does, the behaviour of many operations on `optional` is undefined. + +The following mutating operations never throw exceptions: + +* `optional::operator= ( none_t ) noexcept` +* `optional::reset() noexcept` + +In addition, the following constructors and the destructor never throw exceptions: + +* `optional::optional() noexcept` +* `optional::optional( none_t ) noexcept` + + +Regarding the following assignment functions: * `optional::operator= ( optional const& )` * `optional::operator= ( T const& )` * `template optional::operator= ( optional const& )` * `template optional::operator= ( InPlaceFactory const& )` * `template optional::operator= ( TypedInPlaceFactory const& ) ` -* `optional::reset ( T const&)` +* `optional::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()`) +They forward calls to the corresponding `T`'s constructors or assignments (depending on whether the optional object is initialized or not); so if both `T`'s constructor and the assignment provide strong exception safety guarantee, `optional`'s assignment also provides strong exception safety guarantee; otherwise we only get the basic guarantee. Additionally, if both involved `T`'s constructor and the assignment never throw, `optional`'s assignment also never throws. -On the other hand, the ['uninitializing] methods: +Unless `T`'s constructor or assignment throws, `optional` does not throw anything else on its own. A throw during assignment never changes the initialization state of any optional object involved: -* `optional::operator= ( detail::none_t )` -* `optional::reset()` -Provide the no-throw guarantee (assuming a no-throw `T::~T()`) - -However, since `optional<>` itself doesn't throw any exceptions, the only -source for exceptions here are `T`'s constructor, so if you know the exception -guarantees for `T::T ( T const& )`, you know that `optional`'s assignment and -reset has the same guarantees. - - // - // Case 1: Exception thrown during assignment. - // - T v0(123); - optional opt0(v0); + optional opt1(val1); + optional opt2(val2); + assert(opt1); + assert(opt2); + try { - T v1(456); - optional opt1(v1); - opt0 = opt1 ; - - // If no exception was thrown, assignment succeeded. - assert( *opt0 == v1 ) ; + opt1 = opt2; // throws } catch(...) { - // If any exception was thrown, 'opt0' is reset to uninitialized. - assert( !opt0 ) ; + assert(opt1); + assert(opt2); } - // - // Case 2: Exception thrown during reset(v) - // - T v0(123); - optional opt(v0); - try - { - T v1(456); - opt.reset ( v1 ) ; - - // If no exception was thrown, reset succeeded. - assert( *opt == v1 ) ; - } - catch(...) - { - // If any exception was thrown, 'opt' is reset to uninitialized. - assert( !opt ) ; - } +This also applies to move assignments/constructors. However, move operations are made no-throw more often. [heading Swap] -`void swap( optional&, optional& )` has the same exception guarantee -as `swap(T&,T&)` when both optionals are initialized. -If only one of the optionals is initialized, it gives the same ['basic] -exception guarantee as `optional::reset( T const& )` (since -`optional::reset()` doesn't throw). -If none of the optionals is initialized, it has no-throw guarantee -since it is a no-op. +Unless `swap` on optional is customized, its primary implementation forwards calls to `T`'s `swap` or move constructor (depending on the initialization state of the optional objects). Thus, if both `T`'s `swap` and move constructor never throw, `swap` on `optional` never throws. similarly, if both `T`'s `swap` and move constructor offer strong guarantee, `swap` on `optional` also offers a strong guarantee. +In case `swap` on optional is customized, the call to `T`'s move constructor are replaced with the calls to `T`'s default constructor followed by `swap`. (This is more useful on older compilers that do not support move semantics, when one wants to acheive stronger exception safety guarantees.) In this case the exception safety guarantees for `swap` are reliant on the guarantees of `T`'s `swap` and default constructor [endsect] [section Type requirements] diff --git a/include/boost/optional/optional.hpp b/include/boost/optional/optional.hpp index 0849e90..72f5ab9 100644 --- a/include/boost/optional/optional.hpp +++ b/include/boost/optional/optional.hpp @@ -405,7 +405,7 @@ class optional_base : public optional_tag // Assigns from "none", destroying the current value, if any, leaving this UNINITIALIZED // No-throw (assuming T::~T() doesn't) - void assign ( none_t ) { destroy(); } + void assign ( none_t ) BOOST_NOEXCEPT { destroy(); } #ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT @@ -433,7 +433,7 @@ class optional_base : public optional_tag // Destroys the current value, if any, leaving this UNINITIALIZED // No-throw (assuming T::~T() doesn't) - void reset() { destroy(); } + void reset() BOOST_NOEXCEPT { destroy(); } // Replaces the current value -if any- with 'val' void reset ( argument_type val ) { assign(val); } @@ -892,7 +892,7 @@ class optional : public optional_detail::optional_base // Assigns from a "none" // Which destroys the current value, if any, leaving this UNINITIALIZED // No-throw (assuming T::~T() doesn't) - optional& operator= ( none_t none_ ) + optional& operator= ( none_t none_ ) BOOST_NOEXCEPT { this->assign( none_ ) ; return *this ; diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index d9137bd..7218ffa 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -23,7 +23,6 @@ import testing ; [ run optional_test_io.cpp ] [ run optional_test_move.cpp ] [ run optional_test_equals_none.cpp ] - [ run optional_test_the_compiler.cpp ] [ compile-fail optional_test_fail1.cpp ] [ compile-fail optional_test_fail3a.cpp ] [ compile-fail optional_test_fail3b.cpp ]