In flat_set::assign, the container only provides the basic exception guarantee if memory cannot be stolen from the input and the ::reserve() allocation throws. In addition, since input_view does not specify that its value_type is nothrow move or copyable, the operation may again fail during the translation of elements from the view into the set.
array_.clear();
array_.reserve(input.size()); // <-- might throw here, leaving the container empty
// insert all elements individually
for (auto& element : input.view())
{
if (input.will_copy())
insert(element); // <-- could also throw here, leaving a partially filled container
else
{
// safe, according to precondition of input view,
// we're allowed to move them
auto& non_const = const_cast<Key&>(element);
insert(std::move(non_const)); // <-- or here
}
}
It looks like you are already aware of this, given the TODO comments in flat_map's assign* functions:
template <typename InputIt>
void assign_pair_range(InputIt begin, InputIt end)
{
// TODO: exception safety
clear();
insert_pair_range(begin, end);
}
A simple solution to add strong exception safety would be to create a new flat_set from the input range and swap if there was no exception thrown.
In flat_set::assign, the container only provides the basic exception guarantee if memory cannot be stolen from the input and the ::reserve() allocation throws. In addition, since input_view does not specify that its value_type is nothrow move or copyable, the operation may again fail during the translation of elements from the view into the set.
It looks like you are already aware of this, given the TODO comments in flat_map's assign* functions:
A simple solution to add strong exception safety would be to create a new flat_set from the input range and swap if there was no exception thrown.