@@ -249,9 +249,6 @@ class flat_map {
249
249
250
250
_LIBCPP_HIDE_FROM_ABI flat_map (const flat_map&) = default;
251
251
252
- // The copy/move constructors are not specified in the spec, which means they should be defaulted.
253
- // However, the move constructor can potentially leave a moved-from object in an inconsistent
254
- // state if an exception is thrown.
255
252
_LIBCPP_HIDE_FROM_ABI flat_map (flat_map&& __other) noexcept (
256
253
is_nothrow_move_constructible_v<_KeyContainer> && is_nothrow_move_constructible_v<_MappedContainer> &&
257
254
is_nothrow_move_constructible_v<_Compare>)
@@ -491,19 +488,21 @@ class flat_map {
491
488
return *this ;
492
489
}
493
490
494
- // copy/move assignment are not specified in the spec (defaulted)
495
- // but move assignment can potentially leave moved from object in an inconsistent
496
- // state if an exception is thrown
497
491
_LIBCPP_HIDE_FROM_ABI flat_map& operator =(const flat_map&) = default ;
498
492
499
493
_LIBCPP_HIDE_FROM_ABI flat_map& operator =(flat_map&& __other) noexcept (
500
494
is_nothrow_move_assignable_v<_KeyContainer> && is_nothrow_move_assignable_v<_MappedContainer> &&
501
495
is_nothrow_move_assignable_v<_Compare>) {
496
+ // No matter what happens, we always want to clear the other container before returning
497
+ // since we moved from it
502
498
auto __clear_other_guard = std::__make_scope_guard ([&]() noexcept { __other.clear () /* noexcept */ ; });
503
- auto __clear_self_guard = std::__make_exception_guard ([&]() noexcept { clear () /* noexcept */ ; });
504
- __containers_ = std::move (__other.__containers_ );
505
- __compare_ = std::move (__other.__compare_ );
506
- __clear_self_guard.__complete ();
499
+ {
500
+ // If an exception is thrown, we have no choice but to clear *this to preserve invariants
501
+ auto __on_exception = std::__make_exception_guard ([&]() noexcept { clear () /* noexcept */ ; });
502
+ __containers_ = std::move (__other.__containers_ );
503
+ __compare_ = std::move (__other.__compare_ );
504
+ __on_exception.__complete ();
505
+ }
507
506
return *this ;
508
507
}
509
508
@@ -568,15 +567,15 @@ class flat_map {
568
567
if (__it == end ()) {
569
568
std::__throw_out_of_range (" flat_map::at(const key_type&): Key does not exist" );
570
569
}
571
- return (* __it). second ;
570
+ return __it-> second ;
572
571
}
573
572
574
573
_LIBCPP_HIDE_FROM_ABI const mapped_type& at (const key_type& __x) const {
575
574
auto __it = find (__x);
576
575
if (__it == end ()) {
577
576
std::__throw_out_of_range (" flat_map::at(const key_type&) const: Key does not exist" );
578
577
}
579
- return (* __it). second ;
578
+ return __it-> second ;
580
579
}
581
580
582
581
template <class _Kp >
@@ -586,7 +585,7 @@ class flat_map {
586
585
if (__it == end ()) {
587
586
std::__throw_out_of_range (" flat_map::at(const K&): Key does not exist" );
588
587
}
589
- return (* __it). second ;
588
+ return __it-> second ;
590
589
}
591
590
592
591
template <class _Kp >
@@ -596,7 +595,7 @@ class flat_map {
596
595
if (__it == end ()) {
597
596
std::__throw_out_of_range (" flat_map::at(const K&) const: Key does not exist" );
598
597
}
599
- return (* __it). second ;
598
+ return __it-> second ;
600
599
}
601
600
602
601
// [flat.map.modifiers], modifiers
@@ -805,7 +804,8 @@ class flat_map {
805
804
_LIBCPP_HIDE_FROM_ABI void swap (flat_map& __y) noexcept {
806
805
// warning: The spec has unconditional noexcept, which means that
807
806
// if any of the following functions throw an exception,
808
- // std::terminate will be called
807
+ // std::terminate will be called.
808
+ // This is discussed in P2767, which hasn't been voted on yet.
809
809
ranges::swap (__compare_, __y.__compare_ );
810
810
ranges::swap (__containers_.keys , __y.__containers_ .keys );
811
811
ranges::swap (__containers_.values , __y.__containers_ .values );
@@ -956,8 +956,13 @@ class flat_map {
956
956
return ranges::adjacent_find (__key_container, __greater_or_equal_to) == ranges::end (__key_container);
957
957
}
958
958
959
+ // This function is only used in constructors. So there is not exception handling in this function.
960
+ // If the function exits via an exception, there will be no flat_map object constructed, thus, there
961
+ // is no invariant state to preserve
959
962
_LIBCPP_HIDE_FROM_ABI void __sort_and_unique () {
960
963
auto __zv = ranges::views::zip (__containers_.keys , __containers_.values );
964
+ // To be consistent with std::map's behaviour, we use stable_sort instead of sort.
965
+ // As a result, if there are duplicated keys, the first value in the original order will be taken.
961
966
ranges::stable_sort (__zv, __compare_, [](const auto & __p) -> decltype (auto ) { return std::get<0 >(__p); });
962
967
auto __dup_start = ranges::unique (__zv, __key_equiv (__compare_)).begin ();
963
968
auto __dist = ranges::distance (__zv.begin (), __dup_start);
0 commit comments