This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC 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] Simplify allocator use


On 25/06/14 21:56 +0100, Jonathan Wakely wrote:
The other adds an RAII type to help manage pointers obtained from
allocators. The new type means I can remove several ugly try-catch
blocks that are all very similar in structure and have been bothering
me for some time. The new type also makes it trivial to support
allocators with fancy pointers, fixing long-standing (but not very
important) bugs in std::promise and std::shared_ptr.

This patch applies the __allocated_ptr type to hashtable_policy.h to
remove most explicit deallocation (yay!)  The buckets are still
allocated and deallocated manually, because __allocated_ptr only works
for allocations of single objects, not arrays.

As well as __allocated_ptr this change relies on two things:

1) the node type has a trivial destructor, so we don't actually need
  to call it, we can just reuse or release its storage.
  (See 3.8 [basic.life] p1)

2) allocator_traits::construct and allocator_traits::destroy can be
  used with an allocator that has a different value_type, so we don't
  need to create a rebound copy to destroy every element, we can just
  use the node-allocator.
  (See http://cplusplus.github.io/LWG/lwg-active.html#2218 which is
  Open, but I've discussed the issue with Howard, Pablo and others,
  and I think libc++ already relies on this assumption).

François, could you check it, and let me know if you see anything
wrong or have any comments?

commit d2fd02daab715c79c766bc0a476d1d01da1fc305
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Thu Jun 26 12:28:56 2014 +0100

    	* include/bits/hashtable_policy.h (_ReuseOrAllocNode::operator()): Use
    	__allocated_ptr.
    	(_Hashtable_alloc::_M_allocate_node): Likewise.
    	(_Hashtable_alloc::_M_deallocate_node): Likewise.

diff --git a/libstdc++-v3/include/bits/hashtable_policy.h b/libstdc++-v3/include/bits/hashtable_policy.h
index 606fbab..ed6b2d7 100644
--- a/libstdc++-v3/include/bits/hashtable_policy.h
+++ b/libstdc++-v3/include/bits/hashtable_policy.h
@@ -31,6 +31,8 @@
 #ifndef _HASHTABLE_POLICY_H
 #define _HASHTABLE_POLICY_H 1
 
+#include <bits/allocated_ptr.h>
+
 namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
@@ -137,20 +139,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	      __node_type* __node = _M_nodes;
 	      _M_nodes = _M_nodes->_M_next();
 	      __node->_M_nxt = nullptr;
-	      __value_alloc_type __a(_M_h._M_node_allocator());
-	      __value_alloc_traits::destroy(__a, __node->_M_valptr());
-	      __try
-		{
-		  __value_alloc_traits::construct(__a, __node->_M_valptr(),
-						  std::forward<_Arg>(__arg));
-		}
-	      __catch(...)
-		{
-		  __node->~__node_type();
-		  __node_alloc_traits::deallocate(_M_h._M_node_allocator(),
-						  __node, 1);
-		  __throw_exception_again;
-		}
+	      auto& __a = _M_h._M_node_allocator();
+	      __node_alloc_traits::destroy(__a, __node->_M_valptr());
+	      __allocated_ptr<_NodeAlloc> __guard{__a, __node};
+	      __node_alloc_traits::construct(__a, __node->_M_valptr(),
+					     std::forward<_Arg>(__arg));
+	      __guard = nullptr;
 	      return __node;
 	    }
 	  return _M_h._M_allocate_node(std::forward<_Arg>(__arg));
@@ -1947,33 +1941,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       typename _Hashtable_alloc<_NodeAlloc>::__node_type*
       _Hashtable_alloc<_NodeAlloc>::_M_allocate_node(_Args&&... __args)
       {
-	auto __nptr = __node_alloc_traits::allocate(_M_node_allocator(), 1);
-	__node_type* __n = std::__addressof(*__nptr);
-	__try
-	  {
-	    __value_alloc_type __a(_M_node_allocator());
-	    ::new ((void*)__n) __node_type;
-	    __value_alloc_traits::construct(__a, __n->_M_valptr(),
-					    std::forward<_Args>(__args)...);
-	    return __n;
-	  }
-	__catch(...)
-	  {
-	    __node_alloc_traits::deallocate(_M_node_allocator(), __nptr, 1);
-	    __throw_exception_again;
-	  }
+	auto& __a = _M_node_allocator();
+	auto __guard = std::__allocate_guarded(__a);
+	__node_type* __n = __guard.get();
+	::new ((void*)__n) __node_type;
+	__node_alloc_traits::construct(__a, __n->_M_valptr(),
+				       std::forward<_Args>(__args)...);
+	__guard = nullptr;
+	return __n;
       }
 
   template<typename _NodeAlloc>
     void
     _Hashtable_alloc<_NodeAlloc>::_M_deallocate_node(__node_type* __n)
     {
-      typedef typename __node_alloc_traits::pointer _Ptr;
-      auto __ptr = std::pointer_traits<_Ptr>::pointer_to(*__n);
-      __value_alloc_type __a(_M_node_allocator());
-      __value_alloc_traits::destroy(__a, __n->_M_valptr());
-      __n->~__node_type();
-      __node_alloc_traits::deallocate(_M_node_allocator(), __ptr, 1);
+      static_assert(std::is_trivially_destructible<__node_type>::value,
+		    "Nodes must not require non-trivial destruction");
+      auto& __alloc = _M_node_allocator();
+      __allocated_ptr<__node_alloc_type> __guard{__alloc, __n};
+      __node_alloc_traits::destroy(__alloc, __n->_M_valptr());
     }
 
   template<typename _NodeAlloc>

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