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]

Forward list default default and move constructors


Hi

Here is the patch to default the default and move constructors on the std::forward_list. Putting a move constructor on _Fwd_list_node_base helped limiting the code impact of this patch. It doesn't have any side effect as iterator types using this base type are not defining any move semantic.

I also took the time to optimize the move constructor with allocator when allocator is always equal. It avoids initializing an empty forward list for nothing.

I think it is fine but could we have an abi issue because of the change in forward_list.tcc ?

    * include/bits/forward_list.h
    (_Fwd_list_node_base(_Fwd_list_node_base&&)): New.
    (_Fwd_list_impl()): Add noexcept qualification.
    (_Fwd_list_impl(_Fwd_list_impl&&)): New, default.
    (_Fwd_list_impl(_Fwd_list_impl&&, _Node_alloc_type&&)): New.
    (_Fwd_list_base()): Default.
    (_Fwd_list_base(_Fwd_list_base&&, _Node_alloc_type&&, true_type)): New.
(_Fwd_list_base(_Fwd_list_base&&, _Node_alloc_type&&, false_type)): New.
    (_Fwd_list_base(_Fwd_list_base&& __lst, _Node_alloc_type&& __a)): Use
    latter.
    (_Fwd_list_base(_Fwd_list_base&&)): Default.
    (forward_list<>()): Default.
    (forward_list<>(forward_list&&)): Default.
    * include/bits/forward_list.tcc
(_Fwd_list_base(_Fwd_list_base&&, _Node_alloc_type&&, false_type)): New.
    * testsuite/23_containers/forward_list/allocator/default_init.cc: New.

Tested under Linux x86_64, ok to commit ?

François

diff --git a/libstdc++-v3/include/bits/forward_list.h b/libstdc++-v3/include/bits/forward_list.h
index f319b7f..312cd9e 100644
--- a/libstdc++-v3/include/bits/forward_list.h
+++ b/libstdc++-v3/include/bits/forward_list.h
@@ -53,6 +53,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
   struct _Fwd_list_node_base
   {
     _Fwd_list_node_base() = default;
+    _Fwd_list_node_base(_Fwd_list_node_base&& __x) noexcept
+      : _M_next(__x._M_next)
+    { __x._M_next = nullptr; }
 
     _Fwd_list_node_base* _M_next = nullptr;
 
@@ -284,15 +287,22 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
         _Fwd_list_node_base _M_head;
 
 	_Fwd_list_impl()
-        : _Node_alloc_type(), _M_head()
+	  noexcept( noexcept(_Node_alloc_type()) )
+	: _Node_alloc_type()
 	{ }
 
 	_Fwd_list_impl(const _Node_alloc_type& __a)
-        : _Node_alloc_type(__a), _M_head()
+	: _Node_alloc_type(__a)
+	{ }
+
+	_Fwd_list_impl(_Fwd_list_impl&&) = default;
+
+	_Fwd_list_impl(_Fwd_list_impl&& __fl, _Node_alloc_type&& __a)
+	: _Node_alloc_type(std::move(__a)), _M_head(std::move(__fl._M_head))
 	{ }
 
 	_Fwd_list_impl(_Node_alloc_type&& __a)
-	: _Node_alloc_type(std::move(__a)), _M_head()
+	: _Node_alloc_type(std::move(__a))
 	{ }
       };
 
@@ -311,20 +321,25 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       _M_get_Node_allocator() const noexcept
       { return this->_M_impl; }
 
-      _Fwd_list_base()
-      : _M_impl() { }
+    private:
+      _Fwd_list_base(_Fwd_list_base&& __lst, _Node_alloc_type&& __a, std::true_type)
+	: _M_impl(std::move(__lst._M_impl), std::move(__a))
+      { }
+
+      _Fwd_list_base(_Fwd_list_base&&, _Node_alloc_type&&, std::false_type);
+
+    public:
+      _Fwd_list_base() = default;
 
       _Fwd_list_base(_Node_alloc_type&& __a)
       : _M_impl(std::move(__a)) { }
 
-      _Fwd_list_base(_Fwd_list_base&& __lst, _Node_alloc_type&& __a);
+      _Fwd_list_base(_Fwd_list_base&& __lst, _Node_alloc_type&& __a)
+      : _Fwd_list_base(std::move(__lst), std::move(__a),
+		       typename _Node_alloc_traits::is_always_equal{})
+      { }
 
-      _Fwd_list_base(_Fwd_list_base&& __lst)
-      : _M_impl(std::move(__lst._M_get_Node_allocator()))
-      {
-	this->_M_impl._M_head._M_next = __lst._M_impl._M_head._M_next;
-	__lst._M_impl._M_head._M_next = 0;
-      }
+      _Fwd_list_base(_Fwd_list_base&&) = default;
 
       ~_Fwd_list_base()
       { _M_erase_after(&_M_impl._M_head, 0); }
@@ -436,10 +451,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       /**
        *  @brief  Creates a %forward_list with no elements.
        */
-      forward_list()
-      noexcept(is_nothrow_default_constructible<_Node_alloc_type>::value)
-      : _Base()
-      { }
+      forward_list() = default;
 
       /**
        *  @brief  Creates a %forward_list with no elements.
@@ -532,15 +544,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 
       /**
        *  @brief  The %forward_list move constructor.
-       *  @param  __list  A %forward_list of identical element and allocator
-       *                  types.
+       *  @param  A %forward_list of identical element and allocator types.
        *
-       *  The newly-created %forward_list contains the exact contents of @a
-       *  __list. The contents of @a __list are a valid, but unspecified
-       *  %forward_list.
+       *  The newly-created %forward_list contains the exact contents of the
+       *  moved instance. The content of the moved instance is valid, but
+       *  unspecified %forward_list.
        */
-      forward_list(forward_list&& __list) noexcept
-      : _Base(std::move(__list)) { }
+      forward_list(forward_list&&) = default;
 
       /**
        *  @brief  Builds a %forward_list from an initializer_list
diff --git a/libstdc++-v3/include/bits/forward_list.tcc b/libstdc++-v3/include/bits/forward_list.tcc
index b823b09..95db8a6 100644
--- a/libstdc++-v3/include/bits/forward_list.tcc
+++ b/libstdc++-v3/include/bits/forward_list.tcc
@@ -36,7 +36,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 
   template<typename _Tp, typename _Alloc>
     _Fwd_list_base<_Tp, _Alloc>::
-    _Fwd_list_base(_Fwd_list_base&& __lst, _Node_alloc_type&& __a)
+    _Fwd_list_base(_Fwd_list_base&& __lst, _Node_alloc_type&& __a,
+		   std::false_type)
     : _M_impl(std::move(__a))
     {
       if (__lst._M_get_Node_allocator() == _M_get_Node_allocator())
diff --git a/libstdc++-v3/testsuite/23_containers/forward_list/allocator/default_init.cc b/libstdc++-v3/testsuite/23_containers/forward_list/allocator/default_init.cc
new file mode 100644
index 0000000..b56c9cc
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/forward_list/allocator/default_init.cc
@@ -0,0 +1,67 @@
+// Copyright (C) 2017 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/>.
+
+// { dg-do run { target c++11 } }
+// { dg-options "-O0" }
+// { dg-xfail-run-if "PR c++/65816" { *-*-* } }
+
+#include <forward_list>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+#include <ext/aligned_buffer.h>
+
+using T = int;
+
+using __gnu_test::default_init_allocator;
+
+void test01()
+{
+  typedef default_init_allocator<T> alloc_type;
+  typedef std::forward_list<T, alloc_type> test_type;
+
+  __gnu_cxx::__aligned_buffer<test_type> buf;
+  __builtin_memset(buf._M_addr(), ~0, sizeof(test_type));
+
+  test_type *tmp = ::new(buf._M_addr()) test_type;
+
+  VERIFY( tmp->get_allocator().state == 0 );
+
+  tmp->~test_type();
+}
+
+void test02()
+{
+  typedef default_init_allocator<T> alloc_type;
+  typedef std::forward_list<T, alloc_type> test_type;
+
+  __gnu_cxx::__aligned_buffer<test_type> buf;
+  __builtin_memset(buf._M_addr(), ~0, sizeof(test_type));
+
+  test_type *tmp = ::new(buf._M_addr()) test_type();
+
+  VERIFY( tmp->get_allocator().state == 0 );
+
+  tmp->~test_type();
+}
+
+int main()
+{
+  test01();
+  test02();
+  return 0;
+}


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