This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
[Bug libstdc++/79254] [5/6/7 Regression] basic_string::operator= isn't exception safe
- From: "gcc-bugzilla at daryl dot haresign.com" <gcc-bugzilla at gcc dot gnu dot org>
- To: gcc-bugs at gcc dot gnu dot org
- Date: Fri, 27 Jan 2017 05:48:22 +0000
- Subject: [Bug libstdc++/79254] [5/6/7 Regression] basic_string::operator= isn't exception safe
- Auto-submitted: auto-generated
- References: <bug-79254-4@http.gcc.gnu.org/bugzilla/>
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();
}