diff --git a/stl/inc/flat_set b/stl/inc/flat_set index 67dc93c4da7..1bfb5e191f9 100644 --- a/stl/inc/flat_set +++ b/stl/inc/flat_set @@ -242,11 +242,9 @@ public: } _NODISCARD container_type extract() && { - // The container NEEDS to be cleared no matter what, - // which is not guaranteed by simply moving it away - // ("... valid but unspecified ...") container_type& _Cont = _Get_cont(); - _Clear_scope_guard _Guard{this}; + // always clears the container (N4950 [flat.set.modifiers]/14 and [flat.multiset.modifiers]/10) + _Clear_scope_guard<_Base_flat_set> _Guard{this}; container_type _Temp = _STD move(_Cont); return _Temp; } @@ -405,7 +403,7 @@ public: } private: - void inline _Assert_after_sorted_input() const { + void _Assert_after_sorted_input() const { _STL_ASSERT(_STD is_sorted(begin(), end(), _Get_comp()), "Input was not sorted!"); if constexpr (!_Multi) { _STL_ASSERT(_Is_unique(), "Input was not unique!"); @@ -624,15 +622,21 @@ public: }; _EXPORT_STD template -size_t erase_if(flat_set<_Kty, _Keylt, _Container>& _Val, _Pred _Predicate) { - _Clear_scope_guard _Guard{&_Val}; - return _Erase_remove_if(_Val, _Pass_fn(_Predicate)); +_Container::size_type erase_if(flat_set<_Kty, _Keylt, _Container>& _Val, _Pred _Predicate) { + // clears the container to maintain the invariants when an exception is thrown (N4950 [flat.set.erasure]/5) + _Clear_scope_guard> _Guard{_STD addressof(_Val)}; + const auto _Erased_count = _Erase_remove_if(_Val, _Pass_fn(_Predicate)); + _Guard._Clearable = nullptr; + return _Erased_count; } _EXPORT_STD template -size_t erase_if(flat_multiset<_Kty, _Keylt, _Container>& _Val, _Pred _Predicate) { - _Clear_scope_guard _Guard{&_Val}; - return _Erase_remove_if(_Val, _Pass_fn(_Predicate)); +_Container::size_type erase_if(flat_multiset<_Kty, _Keylt, _Container>& _Val, _Pred _Predicate) { + // clears the container to maintain the invariants when an exception is thrown (N4950 [flat.multiset.erasure]/5) + _Clear_scope_guard> _Guard{_STD addressof(_Val)}; + const auto _Erased_count = _Erase_remove_if(_Val, _Pass_fn(_Predicate)); + _Guard._Clearable = nullptr; + return _Erased_count; } template diff --git a/tests/std/tests/P1222R4_flat_set/test.cpp b/tests/std/tests/P1222R4_flat_set/test.cpp index 6a3ae2e1223..a7739cc7353 100644 --- a/tests/std/tests/P1222R4_flat_set/test.cpp +++ b/tests/std/tests/P1222R4_flat_set/test.cpp @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#include #include #include #include @@ -190,6 +191,24 @@ void test_non_static_comparer() { assert_all_requirements_and_equals(a, {9, 7, 5, -1}); } +template +void test_extract() { + constexpr int elements[]{1, 2, 3, 4}; + C fs{1, 2, 3, 4}; + auto cont = std::move(fs).extract(); + assert(fs.empty()); + assert(ranges::equal(cont, elements)); +} + +template +void test_erase_if() { + constexpr int erased_result[]{1, 3}; + C fs{1, 2, 3, 4}; + erase_if(fs, [](int n) { return n % 2 == 0; }); + assert(fs.size() == 2); + assert(ranges::equal(fs, erased_result)); +} + int main() { test_spaceship_operator>(); test_spaceship_operator>(); @@ -205,6 +224,12 @@ int main() { test_non_static_comparer(); + test_extract>(); + test_extract>(); + + test_erase_if>(); + test_erase_if>(); + assert_basic>(); assert_basic, deque>>();