[PATCH][_GLIBCXX_DEBUG] Hide _Safe_unordered_container methods

Jonathan Wakely jwakely@redhat.com
Thu Mar 5 09:25:38 GMT 2026


On Thu, 05 Mar 2026 at 07:02 +0100, François Dumont wrote:
>libstdc++: [_GLIBCXX_DEBUG] Hide _Safe_unordered_container methods
>
>In _Safe_unordered_container the _M_invalidate_all and _M_invalidate_all_if
>are made public to be used in nested struct _UContMergeGuard.
>
>Thanks to friend declaration we can avoid those method to be accessible from
>user code.
>
>libstdc++-v3/ChangeLog:
>
>        * include/debug/safe_unordered_container.h
>        (_Safe_unordered_container::_UContInvalidatePred): Move 
>outside class, at
>        namespace scope. Declare friend.
>        (_Safe_unordered_container::_UMContInvalidatePred): Likewise.
>        (_Safe_unordered_container::_UContMergeGuard): Likewise.
>        (_Safe_unordered_container::_M_invalidate_all): Make protected.
>        (_Safe_unordered_container::_M_invalidate_all_if): Likewise.
>
>
>Tested under Linux x86_64.
>
>Ok to commit ?
>
>François
>

>diff --git a/libstdc++-v3/include/debug/safe_unordered_container.h b/libstdc++-v3/include/debug/safe_unordered_container.h
>index 3f8346acb3b..66aa29eb84b 100644
>--- a/libstdc++-v3/include/debug/safe_unordered_container.h
>+++ b/libstdc++-v3/include/debug/safe_unordered_container.h
>@@ -36,6 +36,77 @@
>
> namespace __gnu_debug
> {
>+  template<typename _Container>
>+    class _Safe_unordered_container;
>+
>+#if __cplusplus > 201402L

Please change this condition to:

#ifdef __glibcxx_node_extract // >= C++17 && HOSTED

since that's the C++17 feature that these helpers are for.


>+  template<typename _ExtractKey, typename _Source>
>+    struct _UContInvalidatePred
>+    {
>+      template<typename _Iterator>
>+	bool
>+	operator()(_Iterator __it) const
>+	{ return _M_source._M_cont().count(_ExtractKey{}(*__it)) == 0; }
>+
>+      const _Safe_unordered_container<_Source>& _M_source;
>+    };
>+
>+  template<typename _ExtractKey, typename _Source>
>+    struct _UMContInvalidatePred
>+    {
>+      template<typename _Iterator>
>+	bool
>+	operator()(_Iterator __it) const
>+	{
>+	  auto __rng =
>+	    _M_source._M_cont()._M_base().equal_range(_ExtractKey{}(*__it));
>+	  for (auto __rit = __rng.first;
>+	       __rit != __rng.second; ++__rit)
>+	    {
>+	      if (__it == __rit)
>+		return false;
>+	    }
>+
>+	  return true;
>+	}
>+
>+      const _Safe_unordered_container<_Source>& _M_source;
>+    };
>+
>+  template<typename _Source, typename _InvalidatePred>
>+    struct _UContMergeGuard
>+    {
>+      _UContMergeGuard(_Safe_unordered_container<_Source>& __src) noexcept
>+      : _M_source(__src), _M_size(__src._M_cont().size()), _M_pred { __src }
>+      { }
>+
>+      _UContMergeGuard(const _UContMergeGuard&) = delete;
>+
>+      ~_UContMergeGuard()
>+      {
>+	const std::size_t __size = _M_source._M_cont().size();
>+	if (__size == _M_size)
>+	  return;
>+
>+	__try
>+	  {
>+	    if (__size == 0)
>+	      _M_source._M_invalidate_all();
>+	    else
>+	      _M_source._M_invalidate_all_if(_M_pred);
>+	  }
>+	__catch(...)
>+	{
>+	  _M_source._M_invalidate_all();
>+	}
>+      }
>+
>+      _Safe_unordered_container<_Source>& _M_source;
>+      const std::size_t _M_size;
>+      _InvalidatePred _M_pred;
>+  };
>+#endif // C++17
>+
>   /**
>    * @brief Base class for constructing a @a safe unordered container type
>    * that tracks iterators that reference it.
>@@ -57,86 +128,29 @@ namespace __gnu_debug
>   template<typename _Container>
>     class _Safe_unordered_container : public _Safe_unordered_container_base
>     {
>-      _Container&
>-      _M_cont() noexcept
>-      { return *static_cast<_Container*>(this); }
>+      const _Container&
>+      _M_cont() const noexcept
>+      { return *static_cast<const _Container*>(this); }
>
>       const _Safe_unordered_container*
>       _M_self() const
>       { return this; }
>
>-#if __cplusplus > 201402L
>     protected:
>+#if __cplusplus > 201402L

Same change here.

OK for trunk with those changes, thanks.

>       template<typename _ExtractKey, typename _Source>
>-	struct _UContInvalidatePred
>-	{
>-	  template<typename _Iterator>
>-	    bool
>-	    operator()(_Iterator __it) const
>-	    { return _M_source.count(_ExtractKey{}(*__it)) == 0; }
>-
>-	  const _Source& _M_source;
>-	};
>+	friend struct ::__gnu_debug::_UContInvalidatePred;
>
>       template<typename _ExtractKey, typename _Source>
>-	struct _UMContInvalidatePred
>-	{
>-	  template<typename _Iterator>
>-	    bool
>-	    operator()(_Iterator __it) const
>-	    {
>-	      auto __rng =
>-		_M_source._M_base().equal_range(_ExtractKey{}(*__it));
>-	      for (auto __rit = __rng.first;
>-		   __rit != __rng.second; ++__rit)
>-		{
>-		  if (__it == __rit)
>-		    return false;
>-		}
>-
>-	      return true;
>-	    }
>-
>-	  const _Source& _M_source;
>-	};
>+	friend struct ::__gnu_debug::_UMContInvalidatePred;
>
>       template<typename _Source, typename _InvalidatePred>
>-	struct _UContMergeGuard
>-	{
>-	  _UContMergeGuard(_Source& __src) noexcept
>-	  : _M_source(__src), _M_size(__src.size()), _M_pred { __src }
>-	  { }
>-
>-	  _UContMergeGuard(const _UContMergeGuard&) = delete;
>-
>-	  ~_UContMergeGuard()
>-	  {
>-	    const std::size_t __size = _M_source.size();
>-	    if (__size == _M_size)
>-	      return;
>-
>-	    __try
>-	      {
>-		if (__size == 0)
>-		  _M_source._M_invalidate_all();
>-		else
>-		  _M_source._M_invalidate_all_if(_M_pred);
>-	      }
>-	    __catch(...)
>-	      {
>-		_M_source._M_invalidate_all();
>-	      }
>-	  }
>-
>-	  _Source& _M_source;
>-	  const std::size_t _M_size;
>-	  _InvalidatePred _M_pred;
>-	};
>+	friend struct ::__gnu_debug::_UContMergeGuard;
>
>       template<typename _ExtractKey, typename _Source>
> 	static _UContMergeGuard<_Source,
> 				_UContInvalidatePred<_ExtractKey, _Source>>
>-	_S_uc_guard(_ExtractKey, _Source& __src)
>+	_S_uc_guard(_ExtractKey, _Safe_unordered_container<_Source>& __src)
> 	{
> 	  typedef _UContInvalidatePred<_ExtractKey, _Source> _InvalidatePred;
> 	  return _UContMergeGuard<_Source, _InvalidatePred>(__src);
>@@ -145,14 +159,13 @@ namespace __gnu_debug
>       template<typename _ExtractKey, typename _Source>
> 	static _UContMergeGuard<_Source,
> 				_UMContInvalidatePred<_ExtractKey, _Source>>
>-	_S_umc_guard(_ExtractKey, _Source& __src)
>+	_S_umc_guard(_ExtractKey, _Safe_unordered_container<_Source>& __src)
> 	{
> 	  typedef _UMContInvalidatePred<_ExtractKey, _Source> _InvalidatePred;
> 	  return _UContMergeGuard<_Source, _InvalidatePred>(__src);
> 	}
> #endif // C++17
>
>-    public:
>       void
>       _M_invalidate_all()
>       {
>@@ -179,7 +192,6 @@ namespace __gnu_debug
> 	  _M_invalidate_local_if(__pred, sentry);
> 	}
>
>-    protected:
>       template<typename _VictimIt>
> 	void
> 	_M_invalidate(_VictimIt __victim)



More information about the Libstdc++ mailing list