diff --git a/libstdc++-v3/include/bits/basic_string.h b/libstdc++-v3/include/bits/basic_string.h index aa018262c98..c81dc0d425a 100644 --- a/libstdc++-v3/include/bits/basic_string.h +++ b/libstdc++-v3/include/bits/basic_string.h @@ -844,9 +844,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 operator=(basic_string&& __str) noexcept(_Alloc_traits::_S_nothrow_move()) { + const bool __equal_allocs = _Alloc_traits::_S_always_equal() + || _M_get_allocator() == __str._M_get_allocator(); if (!_M_is_local() && _Alloc_traits::_S_propagate_on_move_assign() - && !_Alloc_traits::_S_always_equal() - && _M_get_allocator() != __str._M_get_allocator()) + && !__equal_allocs) { // Destroy existing storage before replacing allocator. _M_destroy(_M_allocated_capacity); @@ -868,16 +869,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 _M_set_length(__str.size()); } } - else if (_Alloc_traits::_S_propagate_on_move_assign() - || _Alloc_traits::_S_always_equal() - || _M_get_allocator() == __str._M_get_allocator()) + else if (_Alloc_traits::_S_propagate_on_move_assign() || __equal_allocs) { // Just move the allocated pointer, our allocator can free it. pointer __data = nullptr; size_type __capacity; if (!_M_is_local()) { - if (_Alloc_traits::_S_always_equal()) + if (__equal_allocs) { // __str can reuse our existing storage. __data = _M_data(); diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/allocator/char/move_assign.cc b/libstdc++-v3/testsuite/21_strings/basic_string/allocator/char/move_assign.cc index cc58348e116..21e0b1cb4f4 100644 --- a/libstdc++-v3/testsuite/21_strings/basic_string/allocator/char/move_assign.cc +++ b/libstdc++-v3/testsuite/21_strings/basic_string/allocator/char/move_assign.cc @@ -28,6 +28,8 @@ const C c = 'a'; using traits = std::char_traits; using __gnu_test::propagating_allocator; +using __gnu_test::tracker_allocator_counter; +using __gnu_test::tracker_allocator; void test01() { @@ -146,10 +148,60 @@ void test03() VERIFY(7 == v8.get_allocator().get_personality()); } +void test04() +{ + typedef propagating_allocator> alloc_type; + typedef std::basic_string test_type; + + { + tracker_allocator_counter::reset(); + test_type v1(alloc_type(1)); + v1 = "abcdefghijklmnopqr10"; + auto ref_alloc_count = tracker_allocator_counter::get_allocation_count(); + + test_type v2(alloc_type(2)); + v2 = "abcdefghijklmnopqr20"; + v2 = std::move(v1); + VERIFY(1 == v1.get_allocator().get_personality()); + VERIFY(1 == v2.get_allocator().get_personality()); + + VERIFY( tracker_allocator_counter::get_allocation_count() == 2 * ref_alloc_count ); + VERIFY( tracker_allocator_counter::get_deallocation_count() == ref_alloc_count ); + + v1 = "abcdefghijklmnopqr11"; + + VERIFY( tracker_allocator_counter::get_allocation_count() == 3 * ref_alloc_count ); + } + + { + tracker_allocator_counter::reset(); + test_type v1(alloc_type(1)); + v1 = "abcdefghijklmnopqr10"; + auto ref_alloc_count = tracker_allocator_counter::get_allocation_count(); + + test_type v2(alloc_type(1)); + v2 = "abcdefghijklmnopqr20"; + v2 = std::move(v1); + VERIFY(1 == v1.get_allocator().get_personality()); + VERIFY(1 == v2.get_allocator().get_personality()); + + VERIFY( tracker_allocator_counter::get_allocation_count() == 2 * ref_alloc_count ); + VERIFY( tracker_allocator_counter::get_deallocation_count() == 0 ); + + v1 = "abcdefghijklmnopqr11"; + + VERIFY( tracker_allocator_counter::get_allocation_count() == 2 * ref_alloc_count ); + } + + VERIFY( tracker_allocator_counter::get_allocation_count() == + tracker_allocator_counter::get_deallocation_count() ); +} + int main() { test01(); test02(); test03(); + test04(); return 0; }