diff options
author | Daniel Trebbien <dtrebbien@gmail.com> | 2018-06-14 09:26:51 +0000 |
---|---|---|
committer | Jonathan Wakely <redi@gcc.gnu.org> | 2018-06-14 10:26:51 +0100 |
commit | 4c1d999a7e937da0d417e8153f54b646603bb210 (patch) | |
tree | a759ed4858add51262b507d4cd3eb47b79f73fad | |
parent | c7a42ade9befecb8fca501b5e2021c09496f3554 (diff) | |
download | gcc-4c1d999a7e937da0d417e8153f54b646603bb210.zip gcc-4c1d999a7e937da0d417e8153f54b646603bb210.tar.gz gcc-4c1d999a7e937da0d417e8153f54b646603bb210.tar.bz2 |
PR libstdc++/83982 fix exception-safety guarantee of std::vector::resize
Construct new elements before moving existing ones, so that if a default
constructor throws, the existing elements are not left in a moved-from
state.
2018-06-14 Daniel Trebbien <dtrebbien@gmail.com>
Jonathan Wakely <jwakely@redhat.com>
PR libstdc++/83982
* include/bits/vector.tcc (vector::_M_default_append(size_type)):
Default-construct new elements before moving existing ones.
* testsuite/23_containers/vector/capacity/resize/strong_guarantee.cc:
New.
Co-Authored-By: Jonathan Wakely <jwakely@redhat.com>
From-SVN: r261585
-rw-r--r-- | libstdc++-v3/ChangeLog | 9 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/vector.tcc | 25 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/23_containers/vector/capacity/resize/strong_guarantee.cc | 60 |
3 files changed, 81 insertions, 13 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 223b327..923841a 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,12 @@ +2018-06-14 Daniel Trebbien <dtrebbien@gmail.com> + Jonathan Wakely <jwakely@redhat.com> + + PR libstdc++/83982 + * include/bits/vector.tcc (vector::_M_default_append(size_type)): + Default-construct new elements before moving existing ones. + * testsuite/23_containers/vector/capacity/resize/strong_guarantee.cc: + New. + 2018-06-13 Jonathan Wakely <jwakely@redhat.com> PR libstdc++/86127 diff --git a/libstdc++-v3/include/bits/vector.tcc b/libstdc++-v3/include/bits/vector.tcc index 1d1ef42..86a7117 100644 --- a/libstdc++-v3/include/bits/vector.tcc +++ b/libstdc++-v3/include/bits/vector.tcc @@ -582,7 +582,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER { if (__n != 0) { - size_type __size = size(); + const size_type __size = size(); size_type __navail = size_type(this->_M_impl._M_end_of_storage - this->_M_impl._M_finish); @@ -601,23 +601,22 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER { const size_type __len = _M_check_len(__n, "vector::_M_default_append"); - const size_type __old_size = __size; pointer __new_start(this->_M_allocate(__len)); - pointer __new_finish(__new_start); + pointer __destroy_from = pointer(); __try { - __new_finish - = std::__uninitialized_move_if_noexcept_a - (this->_M_impl._M_start, this->_M_impl._M_finish, - __new_start, _M_get_Tp_allocator()); - __new_finish = - std::__uninitialized_default_n_a(__new_finish, __n, - _M_get_Tp_allocator()); + std::__uninitialized_default_n_a(__new_start + __size, + __n, _M_get_Tp_allocator()); + __destroy_from = __new_start + __size; + std::__uninitialized_move_if_noexcept_a( + this->_M_impl._M_start, this->_M_impl._M_finish, + __new_start, _M_get_Tp_allocator()); } __catch(...) { - std::_Destroy(__new_start, __new_finish, - _M_get_Tp_allocator()); + if (__destroy_from) + std::_Destroy(__destroy_from, __destroy_from + __n, + _M_get_Tp_allocator()); _M_deallocate(__new_start, __len); __throw_exception_again; } @@ -628,7 +627,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER this->_M_impl._M_end_of_storage - this->_M_impl._M_start); this->_M_impl._M_start = __new_start; - this->_M_impl._M_finish = __new_finish; + this->_M_impl._M_finish = __new_start + __size + __n; this->_M_impl._M_end_of_storage = __new_start + __len; } } diff --git a/libstdc++-v3/testsuite/23_containers/vector/capacity/resize/strong_guarantee.cc b/libstdc++-v3/testsuite/23_containers/vector/capacity/resize/strong_guarantee.cc new file mode 100644 index 0000000..b209d76 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/vector/capacity/resize/strong_guarantee.cc @@ -0,0 +1,60 @@ +// Copyright (C) 2018 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include <vector> +#include <testsuite_hooks.h> + +struct X +{ + X() : data(1) + { + if (fail) + throw 1; + } + + static bool fail; + + std::vector<int> data; +}; + +bool X::fail = false; + +void +test01() +{ + std::vector<X> v(2); + X* const addr = &v[0]; + bool caught = false; + try { + X::fail = true; + v.resize(v.capacity() + 1); // force reallocation + } catch (int) { + caught = true; + } + VERIFY( caught ); + VERIFY( v.size() == 2 ); + VERIFY( &v[0] == addr ); + // PR libstdc++/83982 + VERIFY( ! v[0].data.empty() ); + VERIFY( ! v[1].data.empty() ); +} + +int +main() +{ + test01(); +} |