https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85517

            Bug ID: 85517
           Summary: std::variant exception safety problems
           Product: gcc
           Version: 7.3.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: zhangxy at google dot com
  Target Milestone: ---

There are several issues with the implementation of std::variant related to
exception safety:
1. Copy assignment
According to [variant.assign] 23.7.3.3 (2.4): if either
is_nothrow_copy_constructible_v<Tj> or !is_nothrow_move_constructible_v<Tj>
is true, equivalent to emplace<j>(get<j>(rhs)).

Failure case 1) If Tj is nothrow copy constructible, it should be equivalent to
emplace() which destroys the current content and invoke Tj's copy ctor.
However, the current implementation always copy constructs a temporary variant
and invoke the move constructor. This is unnecessary.

Failure case 2) If Tj's copy ctor throws, *this should be
valueless_by_exception() because emplace() first destroys then invokes the copy
ctor. Since the current implementation copy constructs a temporary variant
first, it has strong guarantee while the standard requires basic guarantee.

2. Conversion assignment operator=(T&&)
According to [variant.assign] 23.7.3.3 (11.3): if is_nothrow_constructible<Tj,
T> == false && is_nothrow_move_constructible<Tj> == true, equivalent to
operator=(variant(std::forward<T>(t))).

Failure case: If Tj has a nothrow move constructor, the standard requires
strong guarantee (that a temporary variant be created first and move it into
*this). The current implementation always invokes emplace(), which has only
basic guarantee.

Reply via email to