mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			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
This commit is contained in:
		
							parent
							
								
									c7a42ade9b
								
							
						
					
					
						commit
						4c1d999a7e
					
				|  | @ -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 | ||||
|  |  | |||
|  | @ -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; | ||||
| 	    } | ||||
| 	} | ||||
|  |  | |||
|  | @ -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(); | ||||
| } | ||||
		Loading…
	
		Reference in New Issue
	
	 Daniel Trebbien
						Daniel Trebbien