From: Paolo Carlini Date: Fri, 9 Dec 2005 18:24:53 +0000 (+0000) Subject: re PR libstdc++/25288 (std::list insert members should have no effects if an exceptio... X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=0cb855b7a607882d78eab29f29eb59275a14141b;p=gcc.git re PR libstdc++/25288 (std::list insert members should have no effects if an exception is thrown) 2005-12-09 Paolo Carlini Howard Hinnant PR libstdc++/25288 * include/bits/stl_list.h (list<>::_M_insert_dispatch, _M_fill_insert): Remove. (_M_initialize_dispatch, _M_fill_initialize): Add. (list(size_type, const value_type&, const allocator_type&), list(const list&), list(_InputIterator, _InputIterator, const allocator_type&): Use the latter. (insert(iterator, size_type, const value_type&), insert(iterator, _InputIterator, _InputIterator)): Use construction & splice. * testsuite/23_containers/list/modifiers/insert/25288.cc: New. * testsuite/testsuite_allocator.h (class throw_allocator): Add. * include/bits/stl_list.h (list<>::insert, erase): Fix wrong comments. Co-Authored-By: Howard Hinnant From-SVN: r108313 --- diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 6785bb39d20..6cedb5e8ddd 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,20 @@ +2005-12-09 Paolo Carlini + Howard Hinnant + + PR libstdc++/25288 + * include/bits/stl_list.h (list<>::_M_insert_dispatch, _M_fill_insert): + Remove. + (_M_initialize_dispatch, _M_fill_initialize): Add. + (list(size_type, const value_type&, const allocator_type&), + list(const list&), list(_InputIterator, _InputIterator, + const allocator_type&): Use the latter. + (insert(iterator, size_type, const value_type&), insert(iterator, + _InputIterator, _InputIterator)): Use construction & splice. + * testsuite/23_containers/list/modifiers/insert/25288.cc: New. + * testsuite/testsuite_allocator.h (class throw_allocator): Add. + + * include/bits/stl_list.h (list<>::insert, erase): Fix wrong comments. + 2005-12-08 Paolo Carlini * include/bits/stl_vector.h (vector<>::size, resize, capacity, diff --git a/libstdc++-v3/include/bits/stl_list.h b/libstdc++-v3/include/bits/stl_list.h index 3d954e98094..f93a03224cc 100644 --- a/libstdc++-v3/include/bits/stl_list.h +++ b/libstdc++-v3/include/bits/stl_list.h @@ -479,7 +479,7 @@ namespace _GLIBCXX_STD list(size_type __n, const value_type& __value = value_type(), const allocator_type& __a = allocator_type()) : _Base(__a) - { this->insert(begin(), __n, __value); } + { _M_fill_initialize(__n, __value); } /** * @brief %List copy constructor. @@ -490,7 +490,7 @@ namespace _GLIBCXX_STD */ list(const list& __x) : _Base(__x.get_allocator()) - { this->insert(begin(), __x.begin(), __x.end()); } + { _M_initialize_dispatch(__x.begin(), __x.end(), __false_type()); } /** * @brief Builds a %list from a range. @@ -500,17 +500,16 @@ namespace _GLIBCXX_STD * Create a %list consisting of copies of the elements from * [@a first,@a last). This is linear in N (where N is * distance(@a first,@a last)). - * - * @if maint - * We don't need any dispatching tricks here, because insert does all of - * that anyway. - * @endif */ template list(_InputIterator __first, _InputIterator __last, const allocator_type& __a = allocator_type()) : _Base(__a) - { this->insert(begin(), __first, __last); } + { + // Check whether it's an integral type. If so, it's not an iterator. + typedef typename std::__is_integer<_InputIterator>::__type _Integral; + _M_initialize_dispatch(__first, __last, _Integral()); + } /** * No explicit dtor needed as the _Base dtor takes care of @@ -798,13 +797,15 @@ namespace _GLIBCXX_STD * This function will insert a specified number of copies of the * given data before the location specified by @a position. * - * Due to the nature of a %list this operation can be done in - * constant time, and does not invalidate iterators and - * references. + * This operation is linear in the number of elements inserted and + * does not invalidate iterators and references. */ void insert(iterator __position, size_type __n, const value_type& __x) - { _M_fill_insert(__position, __n, __x); } + { + list __tmp(__n, __x, get_allocator()); + splice(__position, __tmp); + } /** * @brief Inserts a range into the %list. @@ -816,18 +817,16 @@ namespace _GLIBCXX_STD * first,@a last) into the %list before the location specified by * @a position. * - * Due to the nature of a %list this operation can be done in - * constant time, and does not invalidate iterators and - * references. + * This operation is linear in the number of elements inserted and + * does not invalidate iterators and references. */ template void insert(iterator __position, _InputIterator __first, _InputIterator __last) { - // Check whether it's an integral type. If so, it's not an iterator. - typedef typename std::__is_integer<_InputIterator>::__type _Integral; - _M_insert_dispatch(__position, __first, __last, _Integral()); + list __tmp(__first, __last, get_allocator()); + splice(__position, __tmp); } /** @@ -859,13 +858,12 @@ namespace _GLIBCXX_STD * This function will erase the elements in the range @a * [first,last) and shorten the %list accordingly. * - * Due to the nature of a %list this operation can be done in - * constant time, and only invalidates iterators/references to - * the element being removed. The user is also cautioned that - * this function only erases the elements, and that if the - * elements themselves are pointers, the pointed-to memory is not - * touched in any way. Managing the pointer is the user's - * responsibilty. + * This operation is linear time in the size of the range and only + * invalidates iterators/references to the element being removed. + * The user is also cautioned that this function only erases the + * elements, and that if the elements themselves are pointers, the + * pointed-to memory is not touched in any way. Managing the pointer + * is the user's responsibilty. */ iterator erase(iterator __first, iterator __last) @@ -1071,60 +1069,58 @@ namespace _GLIBCXX_STD sort(_StrictWeakOrdering); protected: - // Internal assign functions follow. + // Internal constructor functions follow. - // Called by the range assign to implement [23.1.1]/9 + // Called by the range constructor to implement [23.1.1]/9 template void - _M_assign_dispatch(_Integer __n, _Integer __val, __true_type) + _M_initialize_dispatch(_Integer __n, _Integer __x, __true_type) { - _M_fill_assign(static_cast(__n), - static_cast(__val)); + _M_fill_initialize(static_cast(__n), + static_cast(__x)); } - // Called by the range assign to implement [23.1.1]/9 + // Called by the range constructor to implement [23.1.1]/9 template void - _M_assign_dispatch(_InputIterator __first, _InputIterator __last, - __false_type); + _M_initialize_dispatch(_InputIterator __first, _InputIterator __last, + __false_type) + { + for (; __first != __last; ++__first) + push_back(*__first); + } - // Called by assign(n,t), and the range assign when it turns out + // Called by list(n,v,a), and the range constructor when it turns out // to be the same thing. void - _M_fill_assign(size_type __n, const value_type& __val); + _M_fill_initialize(size_type __n, const value_type& __x) + { + for (; __n > 0; --__n) + push_back(__x); + } - // Internal insert functions follow. + // Internal assign functions follow. - // Called by the range insert to implement [23.1.1]/9 + // Called by the range assign to implement [23.1.1]/9 template void - _M_insert_dispatch(iterator __pos, _Integer __n, _Integer __x, - __true_type) + _M_assign_dispatch(_Integer __n, _Integer __val, __true_type) { - _M_fill_insert(__pos, static_cast(__n), - static_cast(__x)); + _M_fill_assign(static_cast(__n), + static_cast(__val)); } - // Called by the range insert to implement [23.1.1]/9 + // Called by the range assign to implement [23.1.1]/9 template void - _M_insert_dispatch(iterator __pos, - _InputIterator __first, _InputIterator __last, - __false_type) - { - for (; __first != __last; ++__first) - _M_insert(__pos, *__first); - } + _M_assign_dispatch(_InputIterator __first, _InputIterator __last, + __false_type); - // Called by insert(p,n,x), and the range insert when it turns out + // Called by assign(n,t), and the range assign when it turns out // to be the same thing. void - _M_fill_insert(iterator __pos, size_type __n, const value_type& __x) - { - for (; __n > 0; --__n) - _M_insert(__pos, __x); - } + _M_fill_assign(size_type __n, const value_type& __val); // Moves the elements from [first,last) before position. diff --git a/libstdc++-v3/testsuite/23_containers/list/modifiers/insert/25288.cc b/libstdc++-v3/testsuite/23_containers/list/modifiers/insert/25288.cc new file mode 100644 index 00000000000..a2297180d6b --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/list/modifiers/insert/25288.cc @@ -0,0 +1,92 @@ +// Copyright (C) 2005 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 2, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without Pred 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 COPYING. If not, write to the Free +// Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +// USA. + +// 23.2.2.3 list modifiers [lib.list.modifiers] + +#include +#include +#include + +// libstdc++/25288 +void test01() +{ + bool test __attribute__((unused)) = true; + + typedef __gnu_test::throw_allocator my_alloc; + typedef std::list my_list; + + for (int j = 0; j < 10; ++j) + for (int i = 0; i < 10; ++i) + { + my_alloc alloc1(j + i); + my_list list1(alloc1); + + for (int k = 0; k < j; ++k) + list1.push_back(-(k + 1)); + + try + { + list1.insert(list1.begin(), 10, 99); + VERIFY( false ); + } + catch (std::bad_alloc&) + { + VERIFY( true ); + } + catch (...) + { + VERIFY( false ); + } + + VERIFY( list1.size() == my_list::size_type(j) ); + VERIFY( list1.size() == 0 || list1.back() == -j ); + VERIFY( list1.size() == 0 || list1.front() == -1 ); + + my_alloc alloc2(j + i); + my_list list2(alloc2); + + const int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + for (int k = 0; k < j; ++k) + list2.push_back(-(k + 1)); + + try + { + list2.insert(list2.begin(), data, data + 10); + VERIFY( false ); + } + catch (std::bad_alloc&) + { + VERIFY( true ); + } + catch (...) + { + VERIFY( false ); + } + + VERIFY( list2.size() == my_list::size_type(j) ); + VERIFY( list2.size() == 0 || list2.back() == -j ); + VERIFY( list2.size() == 0 || list2.front() == -1 ); + } +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/testsuite_allocator.h b/libstdc++-v3/testsuite/testsuite_allocator.h index f71a07927da..307a0384dc5 100644 --- a/libstdc++-v3/testsuite/testsuite_allocator.h +++ b/libstdc++-v3/testsuite/testsuite_allocator.h @@ -1,7 +1,7 @@ // -*- C++ -*- // Testing allocator for the C++ library testsuite. // -// Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. +// Copyright (C) 2002, 2003, 2004, 2005 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 @@ -229,6 +229,81 @@ namespace __gnu_test } throw; } + + template + class throw_allocator + { + public: + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef Tp* pointer; + typedef const Tp* const_pointer; + typedef Tp& reference; + typedef const Tp& const_reference; + typedef Tp value_type; + + template + struct rebind + { typedef throw_allocator other; }; + + throw_allocator() throw() + : count(size_type(-1)) { } + + throw_allocator(size_type c) throw() + : count(c) { } + + template + throw_allocator(const throw_allocator& b) throw() + : count(b.get_count()) { } + + size_type get_count() const { return count; } + + pointer + address(reference x) const { return &x; } + + const_pointer + address(const_reference x) const { return &x; } + + pointer + allocate(size_type n, const void* = 0) + { + if (count == 0) + throw std::bad_alloc(); + + if (count != size_type(-1)) + --count; + + return static_cast(::operator new(n * sizeof(Tp))); + } + + void + deallocate(pointer p, size_type) + { ::operator delete(p); } + + size_type + max_size() const throw() + { return size_type(-1) / sizeof(Tp); } + + void + construct(pointer p, const Tp& val) + { ::new(p) Tp(val); } + + void + destroy(pointer p) { p->~Tp(); } + + private: + template + friend inline bool + operator==(const throw_allocator&, const throw_allocator&) + { return true; } + + template + friend inline bool + operator!=(const throw_allocator&, const throw_allocator&) + { return false; } + + size_type count; + }; }; // namespace __gnu_test #endif // _GLIBCXX_TESTSUITE_ALLOCATOR_H