This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [Patch] libstdc++/25288


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]