forked from boostorg/optional
Optional's Assignment fixed
[SVN r28412]
This commit is contained in:
@ -20,6 +20,7 @@ HREF="../../../boost/optional/optional.hpp">boost/optional/optional.hpp</A>>
|
||||
<DT><A HREF="#semantics">Semantics</A></DT>
|
||||
<DT><A HREF="#examples">Examples</A></DT>
|
||||
<DT><A HREF="#ref">Optional references</A></DT>
|
||||
<DT><A HREF="#refassign">Rebinding semantics for assignment of optional references</A></DT>
|
||||
<DT><A HREF="#inplace">In-Place Factories</A></DT>
|
||||
<DT><A HREF="#bool">A note about optional<bool></A></DT>
|
||||
<DT><A HREF="#exsafety">Exception Safety Guarantees</A></DT>
|
||||
@ -35,7 +36,7 @@ HREF="../../../boost/optional/optional.hpp">boost/optional/optional.hpp</A>>
|
||||
|
||||
<P>Consider these functions which should return a value but which might not have
|
||||
a value to return:</P>
|
||||
<pre>(A) double sqrt( double n );
|
||||
<pre>(A) double sqrt(double n );
|
||||
(B) char get_async_input();
|
||||
(C) point polygon::get_any_point_effectively_inside();</pre>
|
||||
<P>There are different approaches to the issue of not having a value to return.</P>
|
||||
@ -100,11 +101,12 @@ if ( p.second )
|
||||
and neither default nor value initialization applies, it is said that the object is
|
||||
<i><b>uninitialized</b></i>. Its actual value exist but has an
|
||||
<i>indeterminate inital value</i> (c.f. 8.5.9).<br>
|
||||
<code>optional<T></code> intends to formalize the notion of initialization/no-initialization
|
||||
<code>optional<T></code> 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 <i>formally</i> uninitialized. A formally uninitialized optional object has conceptually
|
||||
no value at all and this situation can be tested at runtime. It is formally <i>undefined behaviour</i>
|
||||
to try to access the value of an uninitialized optional. An uninitialized optional can be <i>assigned</i> 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 <i>uninitialized</i>.</P>
|
||||
@ -122,8 +124,8 @@ if ( p.second )
|
||||
Using the <a href="../../../doc/html/variant.html">Boost.Variant</a> library, this model can be implemented
|
||||
in terms of <code>boost::variant<T,nil_t></code>.<br>
|
||||
There is precedence for a discriminated union as a model for an optional value: the
|
||||
<a href="http://www.haskell.org/"><u>Haskell</u></a> <b>Maybe</b> builtin type constructor,
|
||||
thus a discriminated union <code>T+nil_t</code> serves as a conceptual foundation.</p>
|
||||
<a href="http://www.haskell.org/"><u>Haskell</u></a> <b>Maybe</b> builtin type constructor.
|
||||
Thus, a discriminated union <code>T+nil_t</code> serves as a conceptual foundation.</p>
|
||||
<p>A <code>variant<T,nil_t></code> follows naturally from the traditional idiom of extending
|
||||
the range of possible values adding an additional sentinel value with the special meaning of <i>Nothing. </i>
|
||||
However, this additional <i>Nothing</i> value is largely irrelevant for our purpose
|
||||
@ -180,33 +182,31 @@ object.</p>
|
||||
<p><b>Direct Value Construction via copy:</b> To introduce a formally
|
||||
initialized wrapped object whose value is obtained as a copy of some object.</p>
|
||||
|
||||
<p><b>Deep Copy Construction:</b> To obtain a different yet equivalent wrapped
|
||||
<p><b>Deep Copy Construction:</b> To obtain a new yet equivalent wrapped
|
||||
object.</p>
|
||||
|
||||
<p><b>Direct Value Assignment (upon initialized):</b> To assign the wrapped object a value obtained
|
||||
as a copy of some object.</p>
|
||||
<p><b>Direct Value Assignment (upon initialized):</b> To assign a value to the wrapped object.</p>
|
||||
|
||||
<p><b>Direct Value Assignment (upon uninitialized):</b> To initialize the wrapped object
|
||||
with a value obtained
|
||||
as a copy of some object.</p>
|
||||
|
||||
<p><b>Assignnment (upon initialized):</b> To assign the wrapped object a value obtained as a copy
|
||||
of another wrapper's object.</p>
|
||||
<p><b>Assignnment (upon initialized):</b> To assign to the wrapped object the value
|
||||
of another wrapped object.</p>
|
||||
|
||||
<p><b>Assignnment (upon uninitialized):</b> To initialize the wrapped object
|
||||
with value obtained as a copy
|
||||
of another wrapper's object.</p>
|
||||
with value of another wrapped object.</p>
|
||||
|
||||
<p><b>Deep Relational Operations (when supported by the type T):</b> To compare
|
||||
wrapped object values taking into account the presence of uninitialized
|
||||
operands.</p>
|
||||
states.</p>
|
||||
|
||||
<p><b>Value access:</b> To unwrap the wrapped object.</p>
|
||||
|
||||
<p><b>Initialization state query:</b> To determine if the object is formally
|
||||
initialized or not.</p>
|
||||
|
||||
<p><b>Swap:</b> To exchange wrapper's objects. (with whatever exception safety
|
||||
<p><b>Swap:</b> To exchange wrapped objects. (with whatever exception safety
|
||||
guarantiees are provided by T's swap).</p>
|
||||
|
||||
<p><b>De-initialization:</b> 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 ) ;</pre>
|
||||
|
||||
<HR>
|
||||
|
||||
<pre>optional<T>::optional( detail::none_t );</pre>
|
||||
<pre>optional<T>::optional( none_t );</pre>
|
||||
<blockquote>
|
||||
<p><b>Effect:</b> Constructs an <b>optional </b>uninitialized.</p>
|
||||
<p><b>Postconditions:</b> <b>*this</b> is <u>uninitialized</u>.</p>
|
||||
@ -436,11 +436,12 @@ assert ( !def ) ;</pre>
|
||||
<blockquote>
|
||||
<p>T's default constructor <u><i>is not</i></u> called.<br>
|
||||
The
|
||||
expression <code>boost::none</code> denotes an instance of <code>boost::detail::none_t</code> that can be
|
||||
expression <code>boost::none</code> denotes an instance of <code>boost::none_t</code> that can be
|
||||
used as the parameter.</p>
|
||||
</blockquote>
|
||||
<p><b>Example:</b></p>
|
||||
<blockquote>
|
||||
<pre>#include <boost/none.hpp></pre>
|
||||
<pre>optional<T> n(none) ;
|
||||
assert ( !n ) ;</pre>
|
||||
</blockquote>
|
||||
@ -468,7 +469,7 @@ assert ( *opt == v ) ;</pre>
|
||||
|
||||
<HR>
|
||||
|
||||
<pre>optional<T&>::optional( T ref )</pre>
|
||||
<pre>optional<T&>::optional( T& ref )</pre>
|
||||
<blockquote>
|
||||
<p><b>Effect:</b> Directly-Constructs an <b>optional</b>.</p>
|
||||
<p><b>Postconditions:</b> <b>*this</b> is <u>initialized</u> and its value is an
|
||||
@ -522,12 +523,11 @@ assert ( init2 == init ) ;
|
||||
<blockquote>
|
||||
<p><b>Effect:</b> Copy-Constructs an <b>optional</b>.</p>
|
||||
<p><b>Postconditions:</b> If <b>rhs</b> is initialized, <b>*this</b> is initialized
|
||||
and its value is a <i>copy</i> of the internal wrapper holding the references in <b>rhs</b>; else <b>*this</b>
|
||||
and its value is another reference to the same object referenced by <b>*rhs</b>; else <b>*this</b>
|
||||
is uninitialized.</p>
|
||||
<p><b>Throws:</b> Nothing.</p>
|
||||
<p><b>Notes:</b> If <b>rhs</b> is initialized, the internal wrapper will be
|
||||
copied and just like true references, both <b>*this</b> and <b>rhs</b> will
|
||||
referr to the same object<b> </b>(will alias).</p>
|
||||
<p><b>Notes:</b> If <b>rhs</b> is initialized, both <b>*this</b> and <b>*rhs</b> will
|
||||
refeer to the same object<b> </b>(they alias).</p>
|
||||
<p><b>Example:</b></p>
|
||||
<blockquote>
|
||||
<pre>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 ) ;
|
||||
|
||||
|
||||
</pre>
|
||||
|
||||
</blockquote>
|
||||
@ -615,22 +622,55 @@ assert ( *y == v ) ;
|
||||
<p><b>Effect:</b> Assigns the value 'rhs' to an <b>optional</b>.</p>
|
||||
<p><b>Postconditions:</b> <b>*this</b> is initialized
|
||||
and its value is a <i>copy</i> of <b>rhs.</b></p>
|
||||
<p><b>Throws:</b> Whatever T::T( T const& ) throws.</p>
|
||||
<p><b>Notes:</b> If <b>*this</b> was initialized, it is first reset to uninitialized
|
||||
using T::~T(), then T::T(<b>rhs</b>) is called.</p>
|
||||
<p><b>Exception Safety:</b> <u>Basic:</u> Exceptions can only be thrown during T::T( T const& );
|
||||
in that case, <b>*this</b> is left <u>uninitialized</u>.
|
||||
</p>
|
||||
<p><b>Throws:</b> Whatever T::operator=( T const& ) or T::T(T conbst&) throws.</p>
|
||||
<p><b>Notes:</b> If <b>*this</b> was initialized, T's assignment operator is
|
||||
used, otherwise, its copy-contructor is used.</p>
|
||||
<p><b>Exception Safety:</b> In the event of an exception, the initialization
|
||||
state of <b>*this</b> is unchanged and its value unspecified as far as optional
|
||||
is concerned (it is up to T's operator=()) [If <b>*this</b> is initially
|
||||
uninitialized and T's <i>copy constructor</i> fails, <b>*this</b> is left
|
||||
properly uninitialized]</p>
|
||||
<p><b>Example:</b></p>
|
||||
<blockquote>
|
||||
<pre>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 ) ;</pre>
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
|
||||
<HR>
|
||||
|
||||
<pre>optional<T&>& optional<T&>::operator= ( T& const& rhs ) ;</pre>
|
||||
<blockquote>
|
||||
<p><b>Effect:</b> (Re)binds thee wrapped reference.</p>
|
||||
<p><b>Postconditions:</b> <b>*this</b> is initialized
|
||||
and it references the same object referenced by <b>rhs.</b></p>
|
||||
<p><b>Notes:</b> If <b>*this</b> was initialized, is is <i>rebound</i> to the
|
||||
new object. See <A HREF="#refassign">here</a> for details on this behaviour.</p>
|
||||
<p><b>Example:</b></p>
|
||||
<blockquote>
|
||||
<pre>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 ) ;
|
||||
</pre>
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
@ -644,21 +684,25 @@ assert ( *opt == y ) ;
|
||||
and its value is a <i>copy</i> of the value of <b>rhs</b>; else <b>*this</b>
|
||||
is uninitialized.
|
||||
</p>
|
||||
<p><b>Throws:</b> Whatever T::T( T const& ) throws.</p>
|
||||
<p><b>Notes:</b> If <b>*this</b> was initialized, it is first reset to uninitialized
|
||||
using T::~T(), then T::T( T const& ) is called if <b>rhs</b> is initialized.
|
||||
</p>
|
||||
<p><b>Exception Safety:</b> <u>Basic:</u> Exceptions can only be thrown during T::T( T const& );
|
||||
in that case, <b>*this</b> is left <u>uninitialized</u>.
|
||||
<p><b>Throws:</b> Whatever T::operator( T const&) or T::T( T const& ) throws.</p>
|
||||
<p><b>Notes:</b> If both<b> *this</b> and <b>rhs</b> are initially initialized,
|
||||
T's <i>assignment</i> <i>operator</i> is used. If <b>*this</b> is initially initialized but <b>
|
||||
rhs</b> is uinitialized, T's <i>destructor</i> is called. If <b>*this</b> is initially
|
||||
uninitialized but rhs is initialized, T's <i>copy constructor</i> is called.
|
||||
</p>
|
||||
<p><b>Exception Safety:</b> In the event of an exception, the initialization
|
||||
state of <b>*this</b> is unchanged and its value unspecified as far as optional
|
||||
is concerned (it is up to T's operator=()) [If <b>*this</b> is initially
|
||||
uninitialized and T's <i>copy constructor</i> fails, <b>*this</b> is left
|
||||
properly uninitialized]</p>
|
||||
<p><b>Example:</b></p>
|
||||
<blockquote>
|
||||
<pre>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'.
|
||||
|
||||
</pre>
|
||||
@ -667,6 +711,40 @@ assert ( !opt ) ;
|
||||
|
||||
<HR>
|
||||
|
||||
<pre>optional<T&> & optional<T&>::operator= ( optional<T&> const& rhs ) ;</pre>
|
||||
<blockquote>
|
||||
<p><b>Effect:</b> (Re)binds thee wrapped reference.</p>
|
||||
<p><b>Postconditions:</b> If <b>*rhs</b> is initialized, *<b>this</b> is initialized
|
||||
and it references the same object referenced by <b>*rhs</b>; otherwise, <b>*this</b>
|
||||
is uninitialized (and references no object).</p>
|
||||
<p><b>Notes:</b> If <b>*this</b> was initialized and so is <b>*rhs</b>, <b>this</b>
|
||||
is is <i>rebound</i> to the new object. See <A HREF="#refassign">here</a> for details on this behaviour.</p>
|
||||
<p><b>Example:</b></p>
|
||||
<blockquote>
|
||||
<pre>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 ) ;
|
||||
</pre>
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
|
||||
<HR>
|
||||
|
||||
<pre>template<U> optional& optional<T <i>(not a ref)</i>>::operator= ( optional<U> const& rhs ) ;</pre>
|
||||
<blockquote>
|
||||
<p><b>Effect:</b> Assigns another <i>convertible</i> <b>optional</b> to an <b>optional</b>.</p>
|
||||
@ -674,14 +752,17 @@ assert ( !opt ) ;
|
||||
and its value is a <i>copy</i> of the value of <b>rhs</b> <i>converted</i>
|
||||
to type T; else <b>*this</b> is uninitialized.
|
||||
</p>
|
||||
<p><b>Throws:</b> Whatever T::T( U const& ) throws.</p>
|
||||
<p><b>Notes:</b> If <b>*this</b> was initialized, it is first reset to uninitialized
|
||||
using T::~T(), then T::T( U const& ) is called if <b>rhs</b> is initialized,
|
||||
which requires a valid conversion from U to T.
|
||||
</p>
|
||||
<p><b>Exception Safety:</b> <u>Basic:</u> Exceptions can only be thrown during T::T( U const& );
|
||||
in that case, <b>*this</b> is left <u>uninitialized</u>.
|
||||
<p><b>Throws:</b> Whatever T::operator=( U const& ) or T::T( U const& ) throws.</p>
|
||||
<p><b>Notes:</b> If both<b> *this</b> and <b>rhs</b> are initially initialized,
|
||||
T's <i>assignment</i> <i>operator</i> (from U) is used. If <b>*this</b> is initially initialized but <b>
|
||||
rhs</b> is uinitialized, T's <i>destructor</i> is called. If <b>*this</b> is initially
|
||||
uninitialized but rhs is initialized, T's <i>converting constructor</i> (from U) is called.
|
||||
</p>
|
||||
<p><b>Exception Safety:</b> In the event of an exception, the initialization
|
||||
state of <b>*this</b> is unchanged and its value unspecified as far as optional
|
||||
is concerned (it is up to T's operator=()) [If <b>*this</b> is initially
|
||||
uninitialized and T's <i>converting constructor</i> fails, <b>*this</b> is left
|
||||
properly uninitialized]</p>
|
||||
<p><b>Example:</b></p>
|
||||
<blockquote>
|
||||
<pre>T v;
|
||||
@ -1118,7 +1199,7 @@ class Fred
|
||||
<HR>
|
||||
|
||||
<H2><A NAME="ref">Optional references</A></H2>
|
||||
<p>This library allow the template parameter T to be of reference type: T&, and
|
||||
<p>This library allows the template parameter T to be of reference type: T&, and
|
||||
to some extent, T const&.</p>
|
||||
|
||||
<p>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: </p>
|
||||
than the reference itself.</li>
|
||||
</ul>
|
||||
|
||||
<HR>
|
||||
<h2><A NAME="refassign">Rebinding semantics for assignment of optional
|
||||
references</a></h2>
|
||||
<p>If you assign to an <i>uninitialized</i> optional<T&> the effect is to bind (for the first time) to the object.
|
||||
Clearly, there is no other choice.</p>
|
||||
<pre>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);
|
||||
</pre>
|
||||
<p>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.</p>
|
||||
<pre>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'
|
||||
</pre>
|
||||
<p>Now, if you assign to an <i>initialized</i> optional<T&>, the effect is to <b>
|
||||
rebind</b> to the new object instead of assigning the referee. This is unlike
|
||||
bare C++ references.</p>
|
||||
<pre>int a = 1 ;
|
||||
int b = 2 ;
|
||||
int& ra = a ;
|
||||
int& rb = b ;
|
||||
optional<int&> ora(ra) ;
|
||||
optional<int&> orb(rb) ;
|
||||
ora = orb ; // 'ora' is <b>rebound</b> to 'b'
|
||||
*ora = 3 ; // Changes value of 'b' (not 'a')
|
||||
assert(a==1);
|
||||
assert(b==3);
|
||||
</pre>
|
||||
<h3>Rationale:</h3>
|
||||
<p>Rebinding semantics for the assignment of <i>initialized</i> optional
|
||||
references has been choosen to provide<b><i> </i>consistency among initialization
|
||||
states<i> </i></b>even at the expense of lack of consistency with the semantics of bare
|
||||
C++ references.<br>
|
||||
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.</p>
|
||||
<p>Imagine optional<T&> fordwarding assignment to the referenced object (thus
|
||||
changing the referenced object value but not rebinding), and consider the
|
||||
following code :</p>
|
||||
<pre> optional<int&> a = get();
|
||||
int x = 1 ;
|
||||
int& rx = x ;
|
||||
optional<int&> b(rx);
|
||||
a = b ;
|
||||
</pre>
|
||||
<p>What does the assignment do?<br>
|
||||
If 'a' is <i>uninitialized</i>, the answer is clear: it binds to 'x' (we now have
|
||||
another reference to 'x').<br>
|
||||
But what if 'a' is already <i>initiliazed? </i>it would change the value of the
|
||||
referenced object (whatever that is); which is inconsistent with the other
|
||||
possible case.</p>
|
||||
<p>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.</p>
|
||||
<p>That is, you would have to discriminate in order to be consistency.<br>
|
||||
<br>
|
||||
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 <i>uninitialized</i> 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.<br>
|
||||
In such scenario, you can assign the value itself directly, as in:</p>
|
||||
<pre>assert(!!opt);
|
||||
*opt=value; </pre>
|
||||
|
||||
<HR>
|
||||
|
||||
<H2><A NAME="inplace">In-Place Factories</A></H2>
|
||||
@ -1152,7 +1312,7 @@ type to be <a href="../../utility/CopyConstructible.html">Copy Constructible</a>
|
||||
constructed object, often temporary, just to follow the copy from:</p>
|
||||
<pre>struct X
|
||||
{
|
||||
X ( int, std::string ) ;
|
||||
X ( int, std:::string ) ;
|
||||
} ;</pre>
|
||||
<pre>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")) ;
|
||||
}
|
||||
</pre>
|
||||
<p>The factories are divided in two groups:<ul>
|
||||
@ -1303,7 +1463,7 @@ of the assignment methods:</p>
|
||||
InPlaceFactory const& ) </code></li>
|
||||
<li> <code>template<class TypedInPlaceFactory> optional<T>::operator= (
|
||||
TypedInPlaceFactory const& ) </code></li>
|
||||
<li> <code>optional<T>::reset ( T const& )</code></li>
|
||||
<li> <code>optional<T>:::reset ( T const&)</code></li>
|
||||
</ul>
|
||||
<p>Can only <i>guarantee</i> the <u>basic exception safety</u>: The lvalue optional is left <u>uninitialized</u>
|
||||
if an exception is thrown (any previous value is <i>first</i> destroyed using T::~T())</p>
|
||||
@ -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 <u>is not</u> required to be <a href="http://www.sgi.com/tech/stl/DefaultConst
|
||||
</blockquote>
|
||||
<HR>
|
||||
|
||||
<P>Revised Jannuary 30, 2004</P>
|
||||
<p><EFBFBD> Copyright Fernando Luis Cacciola Carballal, 2003,2004</p>
|
||||
<P>Revised April 21, 2005</P>
|
||||
<p><EFBFBD> Copyright Fernando Luis Cacciola Carballal, 2003,2004,2005</p>
|
||||
<p> Use, modification, and distribution are subject to the Boost Software
|
||||
License, Version 1.0. (See accompanying file <a href="../../../LICENSE_1_0.txt">
|
||||
LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">
|
||||
|
@ -12,7 +12,7 @@
|
||||
#ifndef BOOST_NONE_17SEP2003_HPP
|
||||
#define BOOST_NONE_17SEP2003_HPP
|
||||
|
||||
#include "boost/detail/none_t.hpp"
|
||||
#include "boost/none_t.hpp"
|
||||
|
||||
// NOTE: Borland users have to include this header outside any precompiled headers
|
||||
// (bcc<=5.64 cannot include instance data in a precompiled header)
|
||||
@ -21,7 +21,7 @@ namespace boost {
|
||||
|
||||
namespace {
|
||||
|
||||
detail::none_t const none = ((detail::none_t)0) ;
|
||||
none_t const none = ((none_t)0) ;
|
||||
|
||||
}
|
||||
|
||||
|
24
include/boost/none_t.hpp
Normal file
24
include/boost/none_t.hpp
Normal file
@ -0,0 +1,24 @@
|
||||
// Copyright (C) 2003, Fernando Luis Cacciola Carballal.
|
||||
//
|
||||
// Use, modification, and distribution is subject to 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)
|
||||
//
|
||||
// See http://www.boost.org/lib/optional for documentation.
|
||||
//
|
||||
// You are welcome to contact the author at:
|
||||
// fernando_cacciola@hotmail.com
|
||||
//
|
||||
#ifndef BOOST_NONE_T_17SEP2003_HPP
|
||||
#define BOOST_NONE_T_17SEP2003_HPP
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace detail { struct none_helper{}; }
|
||||
|
||||
typedef int detail::none_helper::*none_t ;
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
|
@ -26,7 +26,7 @@
|
||||
#include "boost/mpl/bool.hpp"
|
||||
#include "boost/mpl/not.hpp"
|
||||
#include "boost/detail/reference_content.hpp"
|
||||
#include "boost/detail/none_t.hpp"
|
||||
#include "boost/none_t.hpp"
|
||||
#include "boost/utility/compare_pointees.hpp"
|
||||
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, == 1200)
|
||||
@ -167,7 +167,7 @@ class optional_base : public optional_tag
|
||||
|
||||
// Creates an optional<T> uninitialized.
|
||||
// No-throw
|
||||
optional_base ( detail::none_t const& )
|
||||
optional_base ( none_t const& )
|
||||
:
|
||||
m_initialized(false) {}
|
||||
|
||||
@ -208,32 +208,40 @@ class optional_base : public optional_tag
|
||||
~optional_base() { destroy() ; }
|
||||
|
||||
// Assigns from another optional<T> (deep-copies the rhs value)
|
||||
// Basic Guarantee: If T::T( T const& ) throws, this is left UNINITIALIZED
|
||||
void assign ( optional_base const& rhs )
|
||||
{
|
||||
destroy();
|
||||
if (is_initialized())
|
||||
{
|
||||
if ( rhs.is_initialized() )
|
||||
assign_value(rhs.get_impl(), is_reference_predicate() );
|
||||
else destroy();
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( rhs.is_initialized() )
|
||||
construct(rhs.get_impl());
|
||||
}
|
||||
}
|
||||
|
||||
// Assigns from a T (deep-copies the rhs value)
|
||||
// Basic Guarantee: If T::( T const& ) throws, this is left UNINITIALIZED
|
||||
void assign ( argument_type val )
|
||||
{
|
||||
destroy();
|
||||
construct(val);
|
||||
if (is_initialized())
|
||||
assign_value(val, is_reference_predicate() );
|
||||
else construct(val);
|
||||
}
|
||||
|
||||
// Assigns from "none", destroying the current value, if any, leaving this UNINITIALIZED
|
||||
// No-throw (assuming T::~T() doesn't)
|
||||
void assign ( detail::none_t const& ) { destroy(); }
|
||||
void assign ( none_t const& ) { destroy(); }
|
||||
|
||||
#ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT
|
||||
template<class Expr>
|
||||
void assign_expr ( Expr const& expr, Expr const* tag )
|
||||
{
|
||||
destroy();
|
||||
construct(expr,tag);
|
||||
if (is_initialized())
|
||||
assign_expr_to_initialized(expr,tag);
|
||||
else construct(expr,tag);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -244,7 +252,6 @@ class optional_base : public optional_tag
|
||||
void reset() { destroy(); }
|
||||
|
||||
// Replaces the current value -if any- with 'val'
|
||||
// Basic Guarantee: If T::T( T const& ) throws this is left UNINITIALIZED.
|
||||
void reset ( argument_type val ) { assign(val); }
|
||||
|
||||
// Returns a pointer to the value if this is initialized, otherwise,
|
||||
@ -281,6 +288,21 @@ class optional_base : public optional_tag
|
||||
factory.apply(m_storage.address()) ;
|
||||
m_initialized = true ;
|
||||
}
|
||||
|
||||
template<class Expr>
|
||||
void assign_expr_to_initialized ( Expr const& factory, in_place_factory_base const* tag )
|
||||
{
|
||||
destroy();
|
||||
construct(factory,tag);
|
||||
}
|
||||
|
||||
// Constructs in-place using the given typed factory
|
||||
template<class Expr>
|
||||
void assign_expr_to_initialized ( Expr const& factory, typed_in_place_factory_base const* tag )
|
||||
{
|
||||
destroy();
|
||||
construct(factory,tag);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Constructs using any expression implicitely convertible to the single argument
|
||||
@ -294,6 +316,16 @@ class optional_base : public optional_tag
|
||||
m_initialized = true ;
|
||||
}
|
||||
|
||||
// Assigns using a form any expression implicitely convertible to the single argument
|
||||
// of a T's assignment operator.
|
||||
// Converting assignments of optional<T> from optional<U> uses this function with
|
||||
// 'Expr' being of type 'U' and relying on a converting assignment of T from U.
|
||||
template<class Expr>
|
||||
void assign_expr_to_initialized ( Expr const& expr, void const* )
|
||||
{
|
||||
assign_value(expr, is_reference_predicate());
|
||||
}
|
||||
|
||||
#ifdef BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION
|
||||
// BCB5.64 (and probably lower versions) workaround.
|
||||
// The in-place factories are supported by means of catch-all constructors
|
||||
@ -321,6 +353,9 @@ class optional_base : public optional_tag
|
||||
}
|
||||
#endif
|
||||
|
||||
void assign_value ( argument_type val, is_not_reference_tag ) { get_impl() = val; }
|
||||
void assign_value ( argument_type val, is_reference_tag ) { construct(val); }
|
||||
|
||||
void destroy()
|
||||
{
|
||||
if ( m_initialized )
|
||||
@ -391,7 +426,7 @@ class optional : public optional_detail::optional_base<T>
|
||||
|
||||
// Creates an optional<T> uninitialized.
|
||||
// No-throw
|
||||
optional( detail::none_t const& none_ ) : base(none_) {}
|
||||
optional( none_t const& none_ ) : base(none_) {}
|
||||
|
||||
// Creates an optional<T> initialized with 'val'.
|
||||
// Can throw if T::T(T const&) does
|
||||
@ -453,14 +488,7 @@ class optional : public optional_detail::optional_base<T>
|
||||
template<class U>
|
||||
optional& operator= ( optional<U> const& rhs )
|
||||
{
|
||||
this->destroy(); // no-throw
|
||||
|
||||
if ( rhs.is_initialized() )
|
||||
{
|
||||
// An exception can be thrown here.
|
||||
// It it happens, THIS will be left uninitialized.
|
||||
this->assign(rhs.get());
|
||||
}
|
||||
return *this ;
|
||||
}
|
||||
#endif
|
||||
@ -485,7 +513,7 @@ class optional : public optional_detail::optional_base<T>
|
||||
// Assigns from a "none"
|
||||
// Which destroys the current value, if any, leaving this UNINITIALIZED
|
||||
// No-throw (assuming T::~T() doesn't)
|
||||
optional& operator= ( detail::none_t const& none_ )
|
||||
optional& operator= ( none_t const& none_ )
|
||||
{
|
||||
this->assign( none_ ) ;
|
||||
return *this ;
|
||||
@ -607,62 +635,62 @@ bool operator >= ( optional<T> const& x, optional<T> const& y )
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
bool operator == ( optional<T> const& x, detail::none_t const& )
|
||||
bool operator == ( optional<T> const& x, none_t const& )
|
||||
{ return equal_pointees(x, optional<T>() ); }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
bool operator < ( optional<T> const& x, detail::none_t const& )
|
||||
bool operator < ( optional<T> const& x, none_t const& )
|
||||
{ return less_pointees(x,optional<T>() ); }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
bool operator != ( optional<T> const& x, detail::none_t const& y )
|
||||
bool operator != ( optional<T> const& x, none_t const& y )
|
||||
{ return !( x == y ) ; }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
bool operator > ( optional<T> const& x, detail::none_t const& y )
|
||||
bool operator > ( optional<T> const& x, none_t const& y )
|
||||
{ return y < x ; }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
bool operator <= ( optional<T> const& x, detail::none_t const& y )
|
||||
bool operator <= ( optional<T> const& x, none_t const& y )
|
||||
{ return !( y < x ) ; }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
bool operator >= ( optional<T> const& x, detail::none_t const& y )
|
||||
bool operator >= ( optional<T> const& x, none_t const& y )
|
||||
{ return !( x < y ) ; }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
bool operator == ( detail::none_t const& x, optional<T> const& y )
|
||||
bool operator == ( none_t const& x, optional<T> const& y )
|
||||
{ return equal_pointees(optional<T>() ,y); }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
bool operator < ( detail::none_t const& x, optional<T> const& y )
|
||||
bool operator < ( none_t const& x, optional<T> const& y )
|
||||
{ return less_pointees(optional<T>() ,y); }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
bool operator != ( detail::none_t const& x, optional<T> const& y )
|
||||
bool operator != ( none_t const& x, optional<T> const& y )
|
||||
{ return !( x == y ) ; }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
bool operator > ( detail::none_t const& x, optional<T> const& y )
|
||||
bool operator > ( none_t const& x, optional<T> const& y )
|
||||
{ return y < x ; }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
bool operator <= ( detail::none_t const& x, optional<T> const& y )
|
||||
bool operator <= ( none_t const& x, optional<T> const& y )
|
||||
{ return !( y < x ) ; }
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
bool operator >= ( detail::none_t const& x, optional<T> const& y )
|
||||
bool operator >= ( none_t const& x, optional<T> const& y )
|
||||
{ return !( x < y ) ; }
|
||||
|
||||
//
|
||||
@ -679,8 +707,9 @@ namespace optional_detail {
|
||||
#endif
|
||||
|
||||
// optional's swap:
|
||||
// If both are initialized, calls swap(T&, T&), with whatever exception guarantess are given there.
|
||||
// If only one is initialized, calls I.reset() and U.reset(*I), with the Basic Guarantee
|
||||
// If both are initialized, calls swap(T&, T&). If this swap throws, both will remain initialized but their values are now unspecified.
|
||||
// If only one is initialized, calls U.reset(*I), THEN I.reset().
|
||||
// If U.reset(*I) throws, both are left UNCHANGED (U is kept uinitialized and I is never reset)
|
||||
// If both are uninitialized, do nothing (no-throw)
|
||||
template<class T>
|
||||
inline
|
||||
@ -688,12 +717,12 @@ void optional_swap ( optional<T>& x, optional<T>& y )
|
||||
{
|
||||
if ( !x && !!y )
|
||||
{
|
||||
x.reset(*y); // Basic guarantee.
|
||||
x.reset(*y);
|
||||
y.reset();
|
||||
}
|
||||
else if ( !!x && !y )
|
||||
{
|
||||
y.reset(*x); // Basic guarantee.
|
||||
y.reset(*x);
|
||||
x.reset();
|
||||
}
|
||||
else if ( !!x && !!y )
|
||||
|
@ -85,7 +85,7 @@ void test_basics( T const* )
|
||||
optional<T> ob ;
|
||||
|
||||
// Value-Assignment upon Uninitialized optional.
|
||||
// T::T ( T const& x ) is used.
|
||||
// T::T( T const& x ) is used.
|
||||
set_pending_copy( ARG(T) ) ;
|
||||
ob = a ;
|
||||
check_is_not_pending_copy( ARG(T) ) ;
|
||||
@ -93,12 +93,14 @@ void test_basics( T const* )
|
||||
check_value(ob,a,z);
|
||||
|
||||
// Value-Assignment upon Initialized optional.
|
||||
// T::T ( T const& x ) is used
|
||||
set_pending_dtor( ARG(T) ) ;
|
||||
set_pending_copy( ARG(T) ) ;
|
||||
// T::operator=( T const& x ) is used
|
||||
set_pending_assign( ARG(T) ) ;
|
||||
set_pending_copy ( ARG(T) ) ;
|
||||
set_pending_dtor ( ARG(T) ) ;
|
||||
ob = b ;
|
||||
check_is_not_pending_dtor( ARG(T) ) ;
|
||||
check_is_not_pending_copy( ARG(T) ) ;
|
||||
check_is_not_pending_assign( ARG(T) ) ;
|
||||
check_is_pending_copy ( ARG(T) ) ;
|
||||
check_is_pending_dtor ( ARG(T) ) ;
|
||||
check_initialized(ob);
|
||||
check_value(ob,b,z);
|
||||
|
||||
@ -111,13 +113,14 @@ void test_basics( T const* )
|
||||
check_value_const(oa2,a,z);
|
||||
|
||||
// Assignment
|
||||
// T::~T() is used to destroy previous value in ob.
|
||||
// T::T ( T const& x ) is used to copy new value.
|
||||
set_pending_dtor( ARG(T) ) ;
|
||||
set_pending_copy( ARG(T) ) ;
|
||||
// T::operator= ( T const& x ) is used to copy new value.
|
||||
set_pending_assign( ARG(T) ) ;
|
||||
set_pending_copy ( ARG(T) ) ;
|
||||
set_pending_dtor ( ARG(T) ) ;
|
||||
oa = ob ;
|
||||
check_is_not_pending_dtor( ARG(T) ) ;
|
||||
check_is_not_pending_copy( ARG(T) ) ;
|
||||
check_is_not_pending_assign( ARG(T) ) ;
|
||||
check_is_pending_copy ( ARG(T) ) ;
|
||||
check_is_pending_dtor ( ARG(T) ) ;
|
||||
check_initialized(oa);
|
||||
check_value(oa,b,z);
|
||||
|
||||
@ -282,6 +285,9 @@ void test_throwing_direct_init( T const* )
|
||||
BOOST_CHECK(!passed);
|
||||
check_is_not_pending_copy( ARG(T) );
|
||||
check_instance_count(count, ARG(T) );
|
||||
|
||||
reset_throw_on_copy( ARG(T) ) ;
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
@ -317,6 +323,8 @@ void test_throwing_val_assign_on_uninitialized( T const* )
|
||||
check_is_not_pending_copy( ARG(T) );
|
||||
check_instance_count(count, ARG(T) );
|
||||
check_uninitialized(opt);
|
||||
|
||||
reset_throw_on_copy( ARG(T) ) ;
|
||||
}
|
||||
|
||||
//
|
||||
@ -330,11 +338,10 @@ void test_throwing_val_assign_on_initialized( T const* )
|
||||
T z(0);
|
||||
T a(8);
|
||||
T b(9);
|
||||
T x(-1);
|
||||
|
||||
int count = get_instance_count( ARG(T) ) ;
|
||||
|
||||
reset_throw_on_copy( ARG(T) ) ;
|
||||
|
||||
optional<T> opt ( b ) ;
|
||||
++ count ;
|
||||
|
||||
@ -342,16 +349,16 @@ void test_throwing_val_assign_on_initialized( T const* )
|
||||
|
||||
check_value(opt,b,z);
|
||||
|
||||
set_throw_on_copy( ARG(T) ) ;
|
||||
set_throw_on_assign( ARG(T) ) ;
|
||||
|
||||
bool passed = false ;
|
||||
try
|
||||
{
|
||||
// This should:
|
||||
// Attempt to copy construct 'a' and throw.
|
||||
// opt should be left uninitialized (even though it was initialized)
|
||||
set_pending_dtor( ARG(T) ) ;
|
||||
set_pending_copy( ARG(T) ) ;
|
||||
// Attempt to assign 'a' and throw.
|
||||
// opt is kept initialized but its value not neccesarily fully assigned
|
||||
// (in this test, incompletely assigned is flaged with the value -1 being set)
|
||||
set_pending_assign( ARG(T) ) ;
|
||||
opt.reset ( a ) ;
|
||||
passed = true ;
|
||||
}
|
||||
@ -359,12 +366,12 @@ void test_throwing_val_assign_on_initialized( T const* )
|
||||
|
||||
BOOST_CHECK(!passed);
|
||||
|
||||
-- count ;
|
||||
|
||||
check_is_not_pending_dtor( ARG(T) );
|
||||
check_is_not_pending_copy( ARG(T) );
|
||||
check_is_not_pending_assign( ARG(T) );
|
||||
check_instance_count(count, ARG(T) );
|
||||
check_uninitialized(opt);
|
||||
check_initialized(opt);
|
||||
check_value(opt,x,z);
|
||||
|
||||
reset_throw_on_assign ( ARG(T) ) ;
|
||||
}
|
||||
|
||||
//
|
||||
@ -378,8 +385,6 @@ void test_throwing_copy_initialization( T const* )
|
||||
T z(0);
|
||||
T a(10);
|
||||
|
||||
reset_throw_on_copy( ARG(T) ) ;
|
||||
|
||||
optional<T> opt (a);
|
||||
|
||||
int count = get_instance_count( ARG(T) ) ;
|
||||
@ -406,6 +411,8 @@ void test_throwing_copy_initialization( T const* )
|
||||
// Nothing should have happened to the source optional.
|
||||
check_initialized(opt);
|
||||
check_value(opt,a,z);
|
||||
|
||||
reset_throw_on_copy( ARG(T) ) ;
|
||||
}
|
||||
|
||||
//
|
||||
@ -420,8 +427,6 @@ void test_throwing_assign_to_uninitialized( T const* )
|
||||
T z(0);
|
||||
T a(11);
|
||||
|
||||
reset_throw_on_copy( ARG(T) ) ;
|
||||
|
||||
optional<T> opt0 ;
|
||||
optional<T> opt1(a) ;
|
||||
|
||||
@ -446,6 +451,8 @@ void test_throwing_assign_to_uninitialized( T const* )
|
||||
check_is_not_pending_copy( ARG(T) );
|
||||
check_instance_count(count, ARG(T) );
|
||||
check_uninitialized(opt0);
|
||||
|
||||
reset_throw_on_copy( ARG(T) ) ;
|
||||
}
|
||||
|
||||
//
|
||||
@ -460,24 +467,23 @@ void test_throwing_assign_to_initialized( T const* )
|
||||
T z(0);
|
||||
T a(12);
|
||||
T b(13);
|
||||
|
||||
reset_throw_on_copy( ARG(T) ) ;
|
||||
T x(-1);
|
||||
|
||||
optional<T> opt0(a) ;
|
||||
optional<T> opt1(b) ;
|
||||
|
||||
int count = get_instance_count( ARG(T) ) ;
|
||||
|
||||
set_throw_on_copy( ARG(T) ) ;
|
||||
set_throw_on_assign( ARG(T) ) ;
|
||||
|
||||
bool passed = false ;
|
||||
try
|
||||
{
|
||||
// This should:
|
||||
// Attempt to copy construct 'opt1.value()' into opt0 and throw.
|
||||
// opt0 should be left unmodified or uninitialized
|
||||
set_pending_dtor( ARG(T) ) ;
|
||||
set_pending_copy( ARG(T) ) ;
|
||||
// opt0 is kept initialized but its value not neccesarily fully assigned
|
||||
// (in this test, incompletely assigned is flaged with the value -1 being set)
|
||||
set_pending_assign( ARG(T) ) ;
|
||||
opt0 = opt1 ;
|
||||
passed = true ;
|
||||
}
|
||||
@ -486,11 +492,12 @@ void test_throwing_assign_to_initialized( T const* )
|
||||
BOOST_CHECK(!passed);
|
||||
|
||||
// opt0 was left uninitialized
|
||||
-- count ;
|
||||
check_is_not_pending_dtor( ARG(T) );
|
||||
check_is_not_pending_copy( ARG(T) );
|
||||
check_is_not_pending_assign( ARG(T) );
|
||||
check_instance_count(count, ARG(T) );
|
||||
check_uninitialized(opt0);
|
||||
check_initialized(opt0);
|
||||
check_value(opt0,x,z);
|
||||
|
||||
reset_throw_on_assign( ARG(T) ) ;
|
||||
}
|
||||
|
||||
//
|
||||
@ -505,8 +512,6 @@ void test_no_throwing_swap( T const* )
|
||||
T a(14);
|
||||
T b(15);
|
||||
|
||||
reset_throw_on_copy( ARG(T) ) ;
|
||||
|
||||
optional<T> def0 ;
|
||||
optional<T> def1 ;
|
||||
optional<T> opt0(a) ;
|
||||
@ -544,13 +549,12 @@ void test_throwing_swap( T const* )
|
||||
|
||||
T a(16);
|
||||
T b(17);
|
||||
|
||||
reset_throw_on_copy( ARG(T) ) ;
|
||||
T x(-1);
|
||||
|
||||
optional<T> opt0(a) ;
|
||||
optional<T> opt1(b) ;
|
||||
|
||||
set_throw_on_copy( ARG(T) ) ;
|
||||
set_throw_on_assign( ARG(T) ) ;
|
||||
|
||||
//
|
||||
// Case 1: Both Initialized.
|
||||
@ -567,14 +571,18 @@ void test_throwing_swap( T const* )
|
||||
|
||||
BOOST_CHECK(!passed);
|
||||
|
||||
// Assuming swap(T&,T&) has at least the basic guarantee, these should hold.
|
||||
BOOST_CHECK( ( !opt0 || ( !!opt0 && ( ( *opt0 == a ) || ( *opt0 == b ) ) ) ) ) ;
|
||||
BOOST_CHECK( ( !opt1 || ( !!opt1 && ( ( *opt1 == a ) || ( *opt1 == b ) ) ) ) ) ;
|
||||
// optional's swap doesn't affect the initialized states of the arguments. Therefore,
|
||||
// the following must hold:
|
||||
check_initialized(opt0);
|
||||
check_initialized(opt1);
|
||||
check_value(opt0,x,a);
|
||||
check_value(opt1,b,x);
|
||||
|
||||
|
||||
//
|
||||
// Case 2: Only one Initialized.
|
||||
//
|
||||
reset_throw_on_copy( ARG(T) ) ;
|
||||
reset_throw_on_assign( ARG(T) ) ;
|
||||
|
||||
opt0.reset();
|
||||
opt1.reset(a);
|
||||
@ -585,7 +593,7 @@ void test_throwing_swap( T const* )
|
||||
try
|
||||
{
|
||||
// This should attempt to swap optionals and fail at opt0.reset(*opt1)
|
||||
// opt0 should be left uninitialized and opt1 unchanged.
|
||||
// Both opt0 and op1 are left unchanged (unswaped)
|
||||
swap(opt0,opt1);
|
||||
|
||||
passed = true ;
|
||||
@ -596,7 +604,9 @@ void test_throwing_swap( T const* )
|
||||
|
||||
check_uninitialized(opt0);
|
||||
check_initialized(opt1);
|
||||
check_value(opt1,a,b);
|
||||
check_value(opt1,a,x);
|
||||
|
||||
reset_throw_on_copy( ARG(T) ) ;
|
||||
}
|
||||
|
||||
//
|
||||
@ -607,8 +617,6 @@ void test_relops( T const* )
|
||||
{
|
||||
TRACE( std::endl << BOOST_CURRENT_FUNCTION );
|
||||
|
||||
reset_throw_on_copy( ARG(T) ) ;
|
||||
|
||||
T v0(18);
|
||||
T v1(19);
|
||||
T v2(19);
|
||||
|
@ -92,11 +92,23 @@ class X
|
||||
}
|
||||
|
||||
X& operator= ( X const& rhs )
|
||||
{
|
||||
pending_assign = false ;
|
||||
|
||||
if ( throw_on_assign )
|
||||
{
|
||||
TRACE ( "throwing exception in X's assignment" ) ;
|
||||
|
||||
v = -1 ;
|
||||
|
||||
throw 0 ;
|
||||
}
|
||||
else
|
||||
{
|
||||
v = rhs.v ;
|
||||
|
||||
TRACE ( "X::operator =( X const& rhs). this=" << this << " rhs.v=" << rhs.v ) ;
|
||||
|
||||
}
|
||||
return *this ;
|
||||
}
|
||||
|
||||
@ -115,7 +127,9 @@ class X
|
||||
static int count ;
|
||||
static bool pending_copy ;
|
||||
static bool pending_dtor ;
|
||||
static bool pending_assign ;
|
||||
static bool throw_on_copy ;
|
||||
static bool throw_on_assign ;
|
||||
|
||||
private :
|
||||
|
||||
@ -130,27 +144,39 @@ class X
|
||||
int X::count = 0 ;
|
||||
bool X::pending_copy = false ;
|
||||
bool X::pending_dtor = false ;
|
||||
bool X::pending_assign = false ;
|
||||
bool X::throw_on_copy = false ;
|
||||
bool X::throw_on_assign = false ;
|
||||
|
||||
inline void set_pending_copy ( X const* x ) { X::pending_copy = true ; }
|
||||
inline void set_pending_dtor ( X const* x ) { X::pending_dtor = true ; }
|
||||
inline void set_pending_assign ( X const* x ) { X::pending_assign = true ; }
|
||||
inline void set_throw_on_copy ( X const* x ) { X::throw_on_copy = true ; }
|
||||
inline void set_throw_on_assign ( X const* x ) { X::throw_on_assign = true ; }
|
||||
inline void reset_throw_on_copy ( X const* x ) { X::throw_on_copy = false ; }
|
||||
inline void reset_throw_on_assign ( X const* x ) { X::throw_on_assign = false ; }
|
||||
inline void check_is_pending_copy ( X const* x ) { BOOST_CHECK( X::pending_copy ) ; }
|
||||
inline void check_is_pending_dtor ( X const* x ) { BOOST_CHECK( X::pending_dtor ) ; }
|
||||
inline void check_is_not_pending_copy( X const* x ) { BOOST_CHECK( !X::pending_copy ) ; }
|
||||
inline void check_is_not_pending_dtor( X const* x ) { BOOST_CHECK( !X::pending_dtor ) ; }
|
||||
inline void check_is_pending_assign ( X const* x ) { BOOST_CHECK( X::pending_assign ) ; }
|
||||
inline void check_is_not_pending_copy ( X const* x ) { BOOST_CHECK( !X::pending_copy ) ; }
|
||||
inline void check_is_not_pending_dtor ( X const* x ) { BOOST_CHECK( !X::pending_dtor ) ; }
|
||||
inline void check_is_not_pending_assign( X const* x ) { BOOST_CHECK( !X::pending_assign ) ; }
|
||||
inline void check_instance_count ( int c, X const* x ) { BOOST_CHECK( X::count == c ) ; }
|
||||
inline int get_instance_count ( X const* x ) { return X::count ; }
|
||||
|
||||
inline void set_pending_copy (...) {}
|
||||
inline void set_pending_dtor (...) {}
|
||||
inline void set_pending_assign (...) {}
|
||||
inline void set_throw_on_copy (...) {}
|
||||
inline void set_throw_on_assign (...) {}
|
||||
inline void reset_throw_on_copy (...) {}
|
||||
inline void reset_throw_on_assign (...) {}
|
||||
inline void check_is_pending_copy (...) {}
|
||||
inline void check_is_pending_dtor (...) {}
|
||||
inline void check_is_not_pending_copy(...) {}
|
||||
inline void check_is_not_pending_dtor(...) {}
|
||||
inline void check_is_pending_assign (...) {}
|
||||
inline void check_is_not_pending_copy (...) {}
|
||||
inline void check_is_not_pending_dtor (...) {}
|
||||
inline void check_is_not_pending_assign(...) {}
|
||||
inline void check_instance_count (...) {}
|
||||
inline int get_instance_count (...) { return 0 ; }
|
||||
|
||||
|
@ -104,9 +104,16 @@ void test_basics( T const* )
|
||||
|
||||
T z(0);
|
||||
|
||||
T original_a(1);
|
||||
|
||||
T a(1);
|
||||
|
||||
T b(2);
|
||||
|
||||
T c(10);
|
||||
|
||||
T& aref = a ;
|
||||
T& bref = b ;
|
||||
|
||||
// Default construction.
|
||||
// 'def' state is Uninitialized.
|
||||
@ -115,13 +122,16 @@ void test_basics( T const* )
|
||||
check_ref_uninitialized(def);
|
||||
|
||||
// Direct initialization.
|
||||
// 'oa' state is Initialized with 'a'
|
||||
// 'oa' state is Initialized and binds to 'a'
|
||||
// T::T( T const& x ) is NOT used becasue the optional holds a reference.
|
||||
set_pending_copy( ARG(T) ) ;
|
||||
optional<T&> oa ( aref ) ;
|
||||
check_is_pending_copy( ARG(T) );
|
||||
check_ref_initialized(oa);
|
||||
check_ref_value(oa,a,z);
|
||||
*oa = b ; // changes the value of 'a' through the reference
|
||||
BOOST_CHECK( a == b ) ;
|
||||
|
||||
|
||||
// Copy initialization.
|
||||
// T::T ( T const& x ) is NOT used becasue the optional holds a reference.
|
||||
@ -130,27 +140,32 @@ void test_basics( T const* )
|
||||
check_is_pending_copy( ARG(T) ) ;
|
||||
check_ref_initialized_const(oa2);
|
||||
check_ref_value_const(oa2,a,z);
|
||||
*oa2 = original_a ; // restores the value of 'a' through the reference
|
||||
BOOST_CHECK( a == original_a ) ;
|
||||
|
||||
T b(2);
|
||||
optional<T&> ob ;
|
||||
|
||||
// Value-Assignment upon Uninitialized optional.
|
||||
// T::T ( T const& x ) is NOT used becasue the optional holds a reference.
|
||||
set_pending_copy( ARG(T) ) ;
|
||||
ob = a ;
|
||||
ob = a ; // Binds ob to a temporary non-const refererence to 'a'
|
||||
check_is_pending_copy( ARG(T) ) ;
|
||||
check_ref_initialized(ob);
|
||||
check_ref_value(ob,a,z);
|
||||
a = c;
|
||||
check_ref_value(ob,a,z);
|
||||
|
||||
// Value-Assignment upon Initialized optional.
|
||||
// T::T ( T const& x ) is NOT used becasue the optional holds a reference.
|
||||
set_pending_dtor( ARG(T) ) ;
|
||||
set_pending_copy( ARG(T) ) ;
|
||||
ob = b ;
|
||||
check_is_pending_dtor( ARG(T) ) ;
|
||||
check_is_pending_copy( ARG(T) ) ;
|
||||
// T::operator= ( T const& x ) is used.
|
||||
set_pending_assign( ARG(T) ) ;
|
||||
ob = b ; // Rebinds 'ob' to 'b' (without changing 'a')
|
||||
check_is_pending_assign( ARG(T) ) ;
|
||||
check_ref_initialized(ob);
|
||||
check_ref_value(ob,b,z);
|
||||
BOOST_CHECK(a == c); // From a=c in previous test
|
||||
b = c;
|
||||
check_ref_value(ob,b,z);
|
||||
|
||||
|
||||
// Assignment initialization.
|
||||
// T::T ( T const& x ) is NOT used becasue the optional holds a reference.
|
||||
@ -162,14 +177,12 @@ void test_basics( T const* )
|
||||
|
||||
|
||||
// Assignment
|
||||
// T::~T() is used to destroy previous value in ob.
|
||||
// T::T ( T const& x ) is NOT used becasue the optional holds a reference.
|
||||
set_pending_dtor( ARG(T) ) ;
|
||||
set_pending_copy( ARG(T) ) ;
|
||||
oa = ob ;
|
||||
check_is_pending_dtor( ARG(T) ) ;
|
||||
check_is_pending_copy( ARG(T) ) ;
|
||||
// T::operator=( T const& x ) is used.
|
||||
set_pending_assign( ARG(T) ) ;
|
||||
oa = ob ; // Rebinds 'a' to 'b'
|
||||
check_is_pending_assign( ARG(T) ) ;
|
||||
check_ref_initialized(oa);
|
||||
a = original_a ;
|
||||
check_ref_value(oa,b,z);
|
||||
|
||||
// Uninitializing Assignment upon Initialized Optional
|
||||
@ -190,6 +203,7 @@ void test_basics( T const* )
|
||||
check_is_pending_copy( ARG(T) ) ;
|
||||
check_ref_uninitialized(oa);
|
||||
|
||||
|
||||
// Deinitialization of Initialized Optional
|
||||
// T::~T() is NOT used becasue the optional holds a reference.
|
||||
set_pending_dtor( ARG(T) ) ;
|
||||
|
Reference in New Issue
Block a user