@@ -249,9 +249,6 @@ class flat_map {
249249
250250 _LIBCPP_HIDE_FROM_ABI flat_map (const flat_map&) = default;
251251
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.
255252 _LIBCPP_HIDE_FROM_ABI flat_map (flat_map&& __other) noexcept (
256253 is_nothrow_move_constructible_v<_KeyContainer> && is_nothrow_move_constructible_v<_MappedContainer> &&
257254 is_nothrow_move_constructible_v<_Compare>)
@@ -491,19 +488,21 @@ class flat_map {
491488 return *this ;
492489 }
493490
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
497491 _LIBCPP_HIDE_FROM_ABI flat_map& operator =(const flat_map&) = default ;
498492
499493 _LIBCPP_HIDE_FROM_ABI flat_map& operator =(flat_map&& __other) noexcept (
500494 is_nothrow_move_assignable_v<_KeyContainer> && is_nothrow_move_assignable_v<_MappedContainer> &&
501495 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
502498 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+ }
507506 return *this ;
508507 }
509508
@@ -568,15 +567,15 @@ class flat_map {
568567 if (__it == end ()) {
569568 std::__throw_out_of_range (" flat_map::at(const key_type&): Key does not exist" );
570569 }
571- return (* __it). second ;
570+ return __it-> second ;
572571 }
573572
574573 _LIBCPP_HIDE_FROM_ABI const mapped_type& at (const key_type& __x) const {
575574 auto __it = find (__x);
576575 if (__it == end ()) {
577576 std::__throw_out_of_range (" flat_map::at(const key_type&) const: Key does not exist" );
578577 }
579- return (* __it). second ;
578+ return __it-> second ;
580579 }
581580
582581 template <class _Kp >
@@ -586,7 +585,7 @@ class flat_map {
586585 if (__it == end ()) {
587586 std::__throw_out_of_range (" flat_map::at(const K&): Key does not exist" );
588587 }
589- return (* __it). second ;
588+ return __it-> second ;
590589 }
591590
592591 template <class _Kp >
@@ -596,7 +595,7 @@ class flat_map {
596595 if (__it == end ()) {
597596 std::__throw_out_of_range (" flat_map::at(const K&) const: Key does not exist" );
598597 }
599- return (* __it). second ;
598+ return __it-> second ;
600599 }
601600
602601 // [flat.map.modifiers], modifiers
@@ -805,7 +804,8 @@ class flat_map {
805804 _LIBCPP_HIDE_FROM_ABI void swap (flat_map& __y) noexcept {
806805 // warning: The spec has unconditional noexcept, which means that
807806 // 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.
809809 ranges::swap (__compare_, __y.__compare_ );
810810 ranges::swap (__containers_.keys , __y.__containers_ .keys );
811811 ranges::swap (__containers_.values , __y.__containers_ .values );
@@ -956,8 +956,13 @@ class flat_map {
956956 return ranges::adjacent_find (__key_container, __greater_or_equal_to) == ranges::end (__key_container);
957957 }
958958
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
959962 _LIBCPP_HIDE_FROM_ABI void __sort_and_unique () {
960963 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.
961966 ranges::stable_sort (__zv, __compare_, [](const auto & __p) -> decltype (auto ) { return std::get<0 >(__p); });
962967 auto __dup_start = ranges::unique (__zv, __key_equiv (__compare_)).begin ();
963968 auto __dist = ranges::distance (__zv.begin (), __dup_start);
0 commit comments