...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
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:
optional<T>::operator= ( optional<T> const& )
optional<T>::operator= ( T const& )
template<class U> optional<T>::operator= ( optional<U> const& )
template<class InPlaceFactory> optional<T>::operator= ( InPlaceFactory
const&
)
template<class TypedInPlaceFactory> optional<T>::operator= ( TypedInPlaceFactory
const&
)
optional<T>::reset( T const& )
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.
Unless T
's constructor or
assignment throws, assignments to optional<T>
do not throw anything else on its own. A throw during assignment never changes
the initialization state of any optional object involved:
optional<T> opt1(val1); optional<T> opt2(val2); assert(opt1); assert(opt2); try { opt1 = opt2; // throws } catch(...) { assert(opt1); assert(opt2); }
This also applies to move assignments/constructors. However, move operations are made no-throw more often.
Operation emplace
provides
basic exception safety guarantee. If it throws, the optional object becomes
uninitialized regardless of its initial state, and its previous contained
value (if any) is destroyed. It doesn't call any assignment or move/copy
constructor on T
.
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