https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79254
--- Comment #7 from Daryl Haresign <gcc-bugzilla at daryl dot haresign.com> --- I would also be inclined to reverse your Guard: have it take 'this', have an 'activate' method which swaps in the new values, have a 'deactivate' method which releases the memory, and have its destructor swap back the old values. Something like this (formatting and naming aside): void _M_copy_assign(const basic_string& __str, true_type) { struct _Guard { _Guard(basic_string *__s) : _M_self(__s) , _M_alloc(_M_self->_M_get_allocator()) { } ~_Guard() { if (_M_ptr) { _M_self->_M_data(_m_ptr); _M_self->_M_set_length(_M_size) _M_self->_M_get_allocator() = _M_alloc; } } void _M_activate() { _M_ptr = _M_self->_M_data(); _M_size = _M_self->_M_allocated_capacity; _M_self->_M_data(_M_local_data()); _M_self->_M_set_length(0); } void _M_deactivate() { if (_M_ptr) { _Alloc_traits::deallocate(_M_alloc, _M_ptr, _M_size + 1); _M_ptr = nullptr; } } basic_string *_M_self; allocator_type _M_alloc; pointer _M_ptr = nullptr; size_type _M_size = 0; }; _Guard __guard(this); if (!_Alloc_traits::_S_always_equal() && !_M_is_local() && _M_get_allocator() != __str._M_get_allocator()) { // Replacement allocator cannot free existing storage. __guard._M_activate(); } _M_get_allocator() = __str._M_get_allocator(); this->_M_assign(__str); __guard._M_deactivate(); }