123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123 |
-
- [section Optional references]
- [section Overview]
- 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
- some operations are not available in this case:
- * Converting constructors
- * Converting assignment
- * InPlace construction
- * InPlace assignment
- * Value-access via pointer
- Also, even though `optional<T&>` treats it wrapped pseudo-object much as
- a real value, a true real reference is stored so aliasing will ocurr:
- * Copies of `optional<T&>` will copy the references but all these references
- will nonetheless refer to the same object.
- * Value-access will actually provide access to the referenced object
- rather than the reference itself.
- [caution On compilers that do not conform to Standard C++ rules of reference binding, some operations on optional references are disabled in order to prevent subtle bugs. For more details see [link boost_optional.dependencies_and_portability.optional_reference_binding Dependencies and Portability section].]
- [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.
- const int& i = 1; // legal
- optional<const int&> oi = 1; // illegal
- [endsect]
- [section 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; its 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);
- [heading Rationale]
- Rebinding semantics for the assignment of ['initialized ] `optional` references has
- been chosen 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 inconsistent behavior w.r.t to the lvalue initialization state.
- Imagine `optional<T&>` forwarding 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 ['initialized]? 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 explicitly 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 consistent.
- If in your code rebinding to another object is not an option, then it is very
- likely that binding for the first time isn't either. In such case, assignment
- to an ['uninitialized ] `optional<T&>` shall be prohibited. It is quite possible
- that in such a scenario it is a precondition that the lvalue must be already
- initialized. If it isn't, then binding for the first time is OK
- while rebinding is not which is IMO very unlikely.
- In such a scenario, you can assign the value itself directly, as in:
- assert(!!opt);
- *opt=value;
- [endsect]
- [endsect]
|