diff --git a/include/string b/include/string index ba311efa5..9a85797ac 100644 --- a/include/string +++ b/include/string @@ -1367,12 +1367,28 @@ private: _LIBCPP_INLINE_VISIBILITY void __copy_assign_alloc(const basic_string& __str, true_type) { - if (__alloc() != __str.__alloc()) + if (__alloc() == __str.__alloc()) + __alloc() = __str.__alloc(); + else { - clear(); - shrink_to_fit(); + if (!__str.__is_long()) + { + clear(); + shrink_to_fit(); + __alloc() = __str.__alloc(); + } + else + { + allocator_type __a = __str.__alloc(); + pointer __p = __alloc_traits::allocate(__a, __str.__get_long_cap()); + clear(); + shrink_to_fit(); + __alloc() = _VSTD::move(__a); + __set_long_pointer(__p); + __set_long_cap(__str.__get_long_cap()); + __set_long_size(__str.size()); + } } - __alloc() = __str.__alloc(); } _LIBCPP_INLINE_VISIBILITY diff --git a/test/std/strings/basic.string/string.cons/copy_alloc.pass.cpp b/test/std/strings/basic.string/string.cons/copy_alloc.pass.cpp index b3447b94b..092e9f5cb 100644 --- a/test/std/strings/basic.string/string.cons/copy_alloc.pass.cpp +++ b/test/std/strings/basic.string/string.cons/copy_alloc.pass.cpp @@ -18,6 +18,55 @@ #include "test_allocator.h" #include "min_allocator.h" +template +struct alloc_imp { + bool active; + + alloc_imp() : active(true) {} + + T* allocate(std::size_t n) + { + if (active) + return static_cast(std::malloc(n * sizeof(T))); + else + throw std::bad_alloc(); + } + + void deallocate(T* p, std::size_t) { std::free(p); } + void activate () { active = true; } + void deactivate() { active = false; } +}; + +template +struct poca_alloc { + typedef T value_type; + typedef std::true_type propagate_on_container_copy_assignment; + + alloc_imp *imp; + + poca_alloc(alloc_imp *imp) : imp (imp) {} + + template + poca_alloc(const poca_alloc& other) : imp(other.imp) {} + + T* allocate (std::size_t n) { return imp->allocate(n);} + void deallocate(T* p, std::size_t n) { imp->deallocate(p, n); } +}; + +template +bool operator==(const poca_alloc& lhs, const poca_alloc& rhs) +{ + return lhs.imp == rhs.imp; +} + +template +bool operator!=(const poca_alloc& lhs, const poca_alloc& rhs) +{ + return lhs.imp != rhs.imp; +} + + + template void test(S s1, const typename S::allocator_type& a) @@ -29,6 +78,16 @@ test(S s1, const typename S::allocator_type& a) assert(s2.get_allocator() == a); } +#ifndef TEST_HAS_NO_EXCEPTIONS +template +void test_assign(S &s1, const S& s2) +{ + try { s1 = s2; } + catch ( std::bad_alloc &) { return; } + assert(false); +} +#endif + int main() { { @@ -46,5 +105,27 @@ int main() test(S("1"), A()); test(S("1234567890123456789012345678901234567890123456789012345678901234567890"), A()); } + +#ifndef TEST_HAS_NO_EXCEPTIONS + { + typedef poca_alloc A; + typedef std::basic_string, A> S; + const char * p1 = "This is my first string"; + const char * p2 = "This is my second string"; + + alloc_imp imp1; + alloc_imp imp2; + S s1(p1, A(&imp1)); + S s2(p2, A(&imp2)); + + assert(s1 == p1); + assert(s2 == p2); + + imp2.deactivate(); + test_assign(s1, s2); + assert(s1 == p1); + assert(s2 == p2); + } +#endif #endif }