On 12/10/16 22:36 +0200, François Dumont wrote:
On 10/10/2016 23:01, Tim Song wrote:
Trying again...with a few edits.

On Mon, Oct 10, 2016 at 3:24 PM, François Dumont <frs.dum...@gmail.com>
wrote:

@@ -602,24 +612,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
         struct _Rb_tree_impl : public _Node_allocator
         {
   _Key_compare _M_key_compare;
-  _Rb_tree_node_base _M_header;
+  _Rb_header_node _M_header;
+#if __cplusplus < 201103L
   size_type _M_node_count; // Keeps track of size of tree.
+#else
+  size_type _M_node_count = 0; // Keeps track of size of tree.
+#endif

+#if __cplusplus < 201103L
   _Rb_tree_impl()
-  : _Node_allocator(), _M_key_compare(), _M_header(),
-    _M_node_count(0)
-  { _M_initialize(); }
+  : _M_node_count(0)
+  { }
+#else
+  _Rb_tree_impl() = default;
+#endif

The default constructor of the associative containers is required to
value-initialize the comparator (see their synopses in
[map/set/multimap/multiset.overview]).
I don't have latest Standard version so can't see the exact word but I find quite annoying that the Standard doesn't allow this simple implementation.

I don't know if unodered containers have same kind of requirements for equal or hash functors but if so current implementation doesn't do this value initialization.

So here is another attempt. This time it simply allows to have noexcept condition in one place and closer to where operations are being invoked.

Ok to commit after tests ?

François

 _Rb_tree_impl() = default; doesn't do that; it default-initializes the
 comparator instead.

Tim



diff --git a/libstdc++-v3/include/bits/stl_map.h 
b/libstdc++-v3/include/bits/stl_map.h
index e5b2a1b..dea7d5b 100644
--- a/libstdc++-v3/include/bits/stl_map.h
+++ b/libstdc++-v3/include/bits/stl_map.h
@@ -167,11 +167,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
      /**
       *  @brief  Default constructor creates no elements.
       */
-      map()
-      _GLIBCXX_NOEXCEPT_IF(
-         is_nothrow_default_constructible<allocator_type>::value
-         && is_nothrow_default_constructible<key_compare>::value)
-      : _M_t() { }
+#if __cplusplus < 201103L
+      map() : _M_t() { }
+#else
+      map() = default;
+#endif

      /**
       *  @brief  Creates a %map with no elements.
diff --git a/libstdc++-v3/include/bits/stl_multimap.h 
b/libstdc++-v3/include/bits/stl_multimap.h
index d240427..7e86b76 100644
--- a/libstdc++-v3/include/bits/stl_multimap.h
+++ b/libstdc++-v3/include/bits/stl_multimap.h
@@ -164,11 +164,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
      /**
       *  @brief  Default constructor creates no elements.
       */
-      multimap()
-      _GLIBCXX_NOEXCEPT_IF(
-         is_nothrow_default_constructible<allocator_type>::value
-         && is_nothrow_default_constructible<key_compare>::value)
-      : _M_t() { }
+#if __cplusplus < 201103L
+      multimap() : _M_t() { }
+#else
+      multimap() = default;
+#endif

      /**
       *  @brief  Creates a %multimap with no elements.
diff --git a/libstdc++-v3/include/bits/stl_multiset.h 
b/libstdc++-v3/include/bits/stl_multiset.h
index cc068a9..7fe2fbd 100644
--- a/libstdc++-v3/include/bits/stl_multiset.h
+++ b/libstdc++-v3/include/bits/stl_multiset.h
@@ -144,11 +144,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
      /**
       *  @brief  Default constructor creates no elements.
       */
-      multiset()
-      _GLIBCXX_NOEXCEPT_IF(
-         is_nothrow_default_constructible<allocator_type>::value
-         && is_nothrow_default_constructible<key_compare>::value)
-      : _M_t() { }
+#if __cplusplus < 201103L
+      multiset() : _M_t() { }
+#else
+      multiset() = default;
+#endif

      /**
       *  @brief  Creates a %multiset with no elements.
diff --git a/libstdc++-v3/include/bits/stl_set.h 
b/libstdc++-v3/include/bits/stl_set.h
index 3938351..5ed9672 100644
--- a/libstdc++-v3/include/bits/stl_set.h
+++ b/libstdc++-v3/include/bits/stl_set.h
@@ -147,11 +147,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
      /**
       *  @brief  Default constructor creates no elements.
       */
-      set()
-      _GLIBCXX_NOEXCEPT_IF(
-         is_nothrow_default_constructible<allocator_type>::value
-         && is_nothrow_default_constructible<key_compare>::value)
-      : _M_t() { }
+#if __cplusplus < 201103L
+      set() : _M_t() { }
+#else
+      set() = default;
+#endif

      /**
       *  @brief  Creates a %set with no elements.
diff --git a/libstdc++-v3/include/bits/stl_tree.h 
b/libstdc++-v3/include/bits/stl_tree.h
index ee2dc70..b6a3c1e 100644
--- a/libstdc++-v3/include/bits/stl_tree.h
+++ b/libstdc++-v3/include/bits/stl_tree.h
@@ -137,6 +137,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
    }
  };

+  struct _Rb_header_node : public _Rb_tree_node_base
+  {
+    _Rb_header_node() _GLIBCXX_NOEXCEPT
+    {
+      _M_color = _S_red;
+      _M_parent = _Base_ptr();
+      _M_left = _M_right = this;
+    }
+  };
+
  template<typename _Val>
    struct _Rb_tree_node : public _Rb_tree_node_base
    {
@@ -602,24 +612,34 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        struct _Rb_tree_impl : public _Node_allocator
        {
          _Key_compare          _M_key_compare;
-         _Rb_tree_node_base    _M_header;
+         _Rb_header_node       _M_header;
+#if __cplusplus < 201103L
          size_type             _M_node_count; // Keeps track of size of tree.
+#else
+         size_type             _M_node_count = 0; // Keeps track of size of 
tree.
+#endif

          _Rb_tree_impl()
-         : _Node_allocator(), _M_key_compare(), _M_header(),
-           _M_node_count(0)
-         { _M_initialize(); }
+         _GLIBCXX_NOEXCEPT_IF(
+           is_nothrow_default_constructible<_Node_allocator>::value
+           && is_nothrow_default_constructible<_Key_compare>::value)
+         : _M_key_compare()
+#if __cplusplus < 201103L
+         , _M_node_count(0)
+#endif
+         { }

I still think this part is pointless. Why use conditional compilation
here, when we could just always set it to zero?

What is the advantage of using #if here, except adding more lines of
code?


          _Rb_tree_impl(const _Key_compare& __comp, const _Node_allocator& __a)
-         : _Node_allocator(__a), _M_key_compare(__comp), _M_header(),
-           _M_node_count(0)
-         { _M_initialize(); }
+         : _Node_allocator(__a), _M_key_compare(__comp)
+#if __cplusplus < 201103L
+         , _M_node_count(0)
+#endif
+         { }

#if __cplusplus >= 201103L
          _Rb_tree_impl(const _Key_compare& __comp, _Node_allocator&& __a)
-         : _Node_allocator(std::move(__a)), _M_key_compare(__comp),
-           _M_header(), _M_node_count(0)
-         { _M_initialize(); }
+         : _Node_allocator(std::move(__a)), _M_key_compare(__comp)
+         { }
#endif

          void
@@ -630,16 +650,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
            this->_M_header._M_right = &this->_M_header;
            this->_M_node_count = 0;
          }
-
-       private:
-         void
-         _M_initialize()
-         {
-           this->_M_header._M_color = _S_red;
-           this->_M_header._M_parent = 0;
-           this->_M_header._M_left = &this->_M_header;
-           this->_M_header._M_right = &this->_M_header;
- } };

Since we can't remove the constructors that called _M_initialize() we
don't need to get rid of _M_initialize() either. That means we don't
need the _Rb_header_node type (so don't need to produce RTTI for a new
type).

The purpose of the patch is to allow _Rb_tree() = default and then
set() = default, map() = default etc.

That can be done by simply putting the _GLIBCXX_NOEXCEPT_IF on
_Rb_tree_impl() and forgetting all the other changes to _Rb_tree_impl.
Using a default member initializer for _M_node_count and removing
_M_initialize() aren't necessary to achieve the purpose of the patch.




Reply via email to