[Patch] libstdc++/25288
Howard Hinnant
hhinnant@apple.com
Thu Dec 8 21:48:00 GMT 2005
Fwiw, I like to keep try/catch clauses out of "exception neutral"
code - code that is going to just clean up and throw the same
exception. You might do this in this circumstance by changing the
range constructor to just do continual push_back's (almost exactly
like the original insert you're replacing). And then insert can
simply become:
list __temp(__first, __last, get_allocator()); // optimize that
get_allocator call?
splice(__pos, __temp);
Note that you won't need try/catch in the range ctor either. Your
existing (well-designed) _List_base will clean up any mess if the
range ctor throws (if I'm glancing at it correctly).
Fwiw, this particular technique is only a really good deal because
your temp construction is practically free when you have an empty
allocator and empty range - practically free because of the embedded
end-node design. Fast no-throw "default" constructions are worth
their weight in gold! :-)
I'm not positive about my suggested replacement, but your proposed
replacement is definitely too big to inline. Even my suggestion may
be too big to inline. You might try disassembling it on your
favorite platform and counting (optimized but outlined)
instructions. If there's much more than a dozen, I'd be tempted to
outline it. That result may depend on whether the constructor and
splice should be outlined or not.
hth.
-Howard
On Dec 8, 2005, at 1:55 PM, Paolo Carlini wrote:
> Hi,
>
> the below is what I have for the issue: see 23.2.2.3/1. Probably,
> resolving libstdc++/21772 will obsolete the basic testing allocator
> provided by submitter, but for the time being seems sufficient for
> the job.
>
> Anyway, looks fine to everyone? Anything simpler? Otherwise I will go
> ahead for mainline. After a bit of testing seems suited also for
> 4_1-branch.
>
> Paolo.
>
> ///////////////////
> 2005-12-09 Paolo Carlini <pcarlini@suse.de>
>
> PR libstdc++/25288
> * include/bits/stl_list.h (list<>::_M_insert_dispatch(__false_type),
> _M_fill_insert): If _M_create_node throws, erase the elements just
> inserted.
> * testsuite/23_containers/list/modifiers/insert/25288.cc: New.
> * testsuite/testsuite_allocator.h (class throw_allocator):
> Add.Index: include/bits/stl_list.h
> ===================================================================
> --- include/bits/stl_list.h (revision 108226)
> +++ include/bits/stl_list.h (working copy)
> @@ -1113,8 +1113,23 @@
> _InputIterator __first, _InputIterator __last,
> __false_type)
> {
> - for (; __first != __last; ++__first)
> - _M_insert(__pos, *__first);
> + iterator __tmp(__pos);
> + try
> + {
> + if (__first != __last)
> + {
> + __tmp = insert(__pos, *__first);
> + ++__first;
> + }
> +
> + for (; __first != __last; ++__first)
> + _M_insert(__pos, *__first);
> + }
> + catch(...)
> + {
> + erase(__tmp, __pos);
> + __throw_exception_again;
> + }
> }
>
> // Called by insert(p,n,x), and the range insert when it
> turns out
> @@ -1122,8 +1137,23 @@
> void
> _M_fill_insert(iterator __pos, size_type __n, const
> value_type& __x)
> {
> - for (; __n > 0; --__n)
> - _M_insert(__pos, __x);
> + iterator __tmp(__pos);
> + try
> + {
> + if (__n)
> + {
> + __tmp = insert(__pos, __x);
> + --__n;
> + }
> +
> + for (; __n > 0; --__n)
> + _M_insert(__pos, __x);
> + }
> + catch(...)
> + {
> + erase(__tmp, __pos);
> + __throw_exception_again;
> + }
> }
>
>
> Index: testsuite/23_containers/list/modifiers/insert/25288.cc
> ===================================================================
> --- testsuite/23_containers/list/modifiers/insert/25288.cc
> (revision 0)
> +++ testsuite/23_containers/list/modifiers/insert/25288.cc
> (revision 0)
> @@ -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 <list>
> +#include <testsuite_hooks.h>
> +#include <testsuite_allocator.h>
> +
> +// libstdc++/25288
> +void test01()
> +{
> + bool test __attribute__((unused)) = true;
> +
> + typedef __gnu_test::throw_allocator<int> my_alloc;
> + typedef std::list<int, my_alloc > 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;
> +}
> Index: testsuite/testsuite_allocator.h
> ===================================================================
> --- testsuite/testsuite_allocator.h (revision 108226)
> +++ testsuite/testsuite_allocator.h (working copy)
> @@ -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 @@
> }
> throw;
> }
> +
> + template<typename Tp>
> + 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<typename Tp1>
> + struct rebind
> + { typedef throw_allocator<Tp1> other; };
> +
> + throw_allocator() throw()
> + : count(size_type(-1)) { }
> +
> + throw_allocator(size_type c) throw()
> + : count(c) { }
> +
> + template<typename Tp1>
> + throw_allocator(const throw_allocator<Tp1>& 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<Tp*>(::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<typename Tp1>
> + friend inline bool
> + operator==(const throw_allocator&, const
> throw_allocator<Tp1>&)
> + { return true; }
> +
> + template<typename Tp1>
> + friend inline bool
> + operator!=(const throw_allocator&, const
> throw_allocator<Tp1>&)
> + { return false; }
> +
> + size_type count;
> + };
> }; // namespace __gnu_test
>
> #endif // _GLIBCXX_TESTSUITE_ALLOCATOR_H
More information about the Libstdc++
mailing list