[PATCH] Implement std::__debug::inplace_vector

François Dumont frs.dumont@gmail.com
Mon Nov 3 06:08:30 GMT 2025


On 11/2/25 04:09, Jonathan Wakely wrote:
>
>
> On Sat, 1 Nov 2025, 21:10 François Dumont, <frs.dumont@gmail.com> wrote:
>
>     Hi
>
>     Here is the implementation of the std::__debug::inplace_vector.
>
>
> It looks like this is going to repeat the assertions in e.g. 
> operator[], front, back etc because those already have assertions in 
> the base class.

This is I think unavoidable if you want to cover direct usages of 
__gnu_debug::inplace_vector like in 
23_containers/inplace_vector/debug/invalidation/*.cc tests.

>
>
>     I eventually had to introduce a dedicated std::erase_if/std::erase
>     implementation for the __debug version. When directly using
>     __gnu_debug::inplace_vector the std::erase_if was used downcasting the
>
>
> If it's converting to a base, it's upcasting.
>
>
>     inplace_vector into the std::inplace_vector base class so breaking
>     encapsulation. So we really need dedicated implementations and I'll
>     prepare patches for other containers.
>
>
> Why is the implicit cast a problem? We know that erase_if doesn't 
> iterate past the end, and only dereferences valid iterators. That's 
> one of the benefits of using erase_if: it ensures the container is 
> accessed safely.
The problem is that the std::__debug::inplace_vector is not aware of the 
invalidated iterators.
>
> Is encapsulation broken if a standard library function does that 
> implicit cast? Is it observable to users?
Yes, some iterators might not be invalidated as they should.
>
>
>
>     I also added tests for std::swap. Overloading it in std:: namespace
>     seems the best option to me. If it is defined in std::__debug:: as it
>     should then calls to std::swap in user code are replaced by the
>     generic
>     call to swap in move.h instead of calling inplace_vector<>::swap. 
>
>
> Users should call swap not std::swap. That was the consensus when LWG 
> discussed https://cplusplus.github.io/LWG/issue4250

Ok, I'll remove the test case with the call to std::swap then.


>
>     It
>     still works to invalidate iterators but is a major performance
>     issue. I
>     noticed this running in gdb, is there a way to test for call to the
>     correct swap ?
>
>     I also wonder in
>     testsuite/23_containers/inplace_vector/debug/invalidation/swap.cc
>     test02
>     how gcc does to find the proper swap method on the unqualified call ?
>
>
> Argument Dependent Lookup ?

That's what it should be but container is in std::__debug:: whereas the 
swap definition is in std::.

I'll have some more tests but with your remark above I think I'll just 
defined swap as friend in std::__debug::inplace_vector like it's done in 
std::inplace_vector.


>
>
>          Add _GLIBCXX_DEBUG std::inplace_vector implementation.
>
>          Unlike other _GLIBCXX_DEBUG containers the
>     std::__debug::inplace_vector is
>          inheriting privately from both __gnu_debug::_Safe_sequence<> and
>     std::inplace_vector
>          classes to preserve encapsulation. Iterators won't be created or
>     invalidated without
>     std::__debug::inplace_vector being aware. However
>     std::__debug::inplace_vector<T, 0>
>          inherits publicly from std::inplace_vector<T, 0> to benefit from
>     the same std::
>          functions overloads.
>
>          libstdc++-v3/ChangeLog:
>
>                  * include/Makefile.am (debug_headers): Add
>     inplace_vector.
>                  * include/Makefile.in: Regenerate.
>                  * include/debug/inplace_vector: New.
>                  * include/debug/safe_base.h (~_Safe_sequence_base()):
>     Add
>     C++11 noexcept
>                  qualification.
>                  (_Safe_sequence_base::operator=(const
>     _Safe_sequence_base&)): New.
>     (_Safe_sequence_base::operator=(_Safe_sequence_base&&)): New.
>                  (_Safe_sequence_base::_M_invalidate_all): Add C++20
>     constexpr qualification.
>                  * include/debug/safe_container.h
>                  (_Safe_container::operator=(const _Safe_container&)):
>     Implement using same
>                  _Safe_sequence_base operator.
>                  * include/std/inplace_vector
>     [_GLIBCXX_DEBUG](std::inplace_vector<>): Move
>                  implementation into __cxx1998 namespace.
>                  (erase, erase_if): Limit to non-debug inplace_vector<>,
>     cleanup code.
>                  [_GLIBCXX_DEBUG]: Add include <debug/inplace_vector>.
>                  * testsuite/23_containers/inplace_vector/cons/1.cc:
>     Adapt,
>     skip several
>                  is_trivially_xxx checks when in _GLIBCXX_DEBUG mode.
>                  * testsuite/23_containers/inplace_vector/copy.cc:
>     Likewise.
>                  * testsuite/23_containers/inplace_vector/move.cc:
>     Likewise.
>                  *
>     testsuite/23_containers/inplace_vector/debug/assign1_neg.cc: New
>     test case.
>                  *
>     testsuite/23_containers/inplace_vector/debug/assign2_neg.cc: New
>     test case.
>                  *
>     testsuite/23_containers/inplace_vector/debug/assign3_neg.cc: New
>     test case.
>                  *
>     testsuite/23_containers/inplace_vector/debug/assign4_backtrace_neg.cc:
>
>     New test case.
>                  *
>     testsuite/23_containers/inplace_vector/debug/assign4_neg.cc: New
>     test case.
>                  *
>     testsuite/23_containers/inplace_vector/debug/construct1_neg.cc:
>     New test
>     case.
>                  *
>     testsuite/23_containers/inplace_vector/debug/construct2_neg.cc:
>     New test
>     case.
>                  *
>     testsuite/23_containers/inplace_vector/debug/construct3_neg.cc:
>     New test
>     case.
>                  *
>     testsuite/23_containers/inplace_vector/debug/construct4_neg.cc:
>     New test
>     case.
>                  *
>     testsuite/23_containers/inplace_vector/debug/debug_functions.cc: New
>     test case.
>                  * testsuite/23_containers/inplace_vector/debug/erase.cc:
>     New test case.
>                  *
>     testsuite/23_containers/inplace_vector/debug/insert1_neg.cc: New
>     test case.
>                  *
>     testsuite/23_containers/inplace_vector/debug/insert2_neg.cc: New
>     test case.
>                  *
>     testsuite/23_containers/inplace_vector/debug/insert3_neg.cc: New
>     test case.
>                  *
>     testsuite/23_containers/inplace_vector/debug/insert4_neg.cc: New
>     test case.
>                  *
>     testsuite/23_containers/inplace_vector/debug/insert5_neg.cc: New
>     test case.
>                  *
>     testsuite/23_containers/inplace_vector/debug/insert7_neg.cc: New
>     test case.
>                  *
>     testsuite/23_containers/inplace_vector/debug/invalidation/1.cc:
>     New test
>     case.
>                  *
>     testsuite/23_containers/inplace_vector/debug/invalidation/2.cc:
>     New test
>     case.
>                  *
>     testsuite/23_containers/inplace_vector/debug/invalidation/3.cc:
>     New test
>     case.
>                  *
>     testsuite/23_containers/inplace_vector/debug/invalidation/4.cc:
>     New test
>     case.
>                  *
>     testsuite/23_containers/inplace_vector/debug/invalidation/append_range.cc:
>
>     New test case.
>                  *
>     testsuite/23_containers/inplace_vector/debug/invalidation/erase.cc:
>     New
>     test case.
>                  *
>     testsuite/23_containers/inplace_vector/debug/invalidation/pop_back.cc:
>
>     New test case.
>                  *
>     testsuite/23_containers/inplace_vector/debug/invalidation/push_back.cc:
>
>     New test case.
>                  *
>     testsuite/23_containers/inplace_vector/debug/invalidation/swap.cc:
>     New
>     test case.
>                  *
>     testsuite/23_containers/inplace_vector/debug/invalidation/try_append_range.cc:
>
>     New test case.
>                  *
>     testsuite/23_containers/inplace_vector/debug/invalidation/try_emplace_back.cc:
>
>     New test case.
>                  *
>     testsuite/23_containers/inplace_vector/debug/invalidation/try_push_back.cc:
>
>     New test case.
>                  *
>     testsuite/23_containers/inplace_vector/debug/invalidation/unchecked_emplace_back.cc:
>
>     New test case.
>                  *
>     testsuite/23_containers/inplace_vector/debug/multithreaded_swap.cc:
>     New
>     test case.
>                  * testsuite/util/debug/checks.h: Avoid using
>     _GLIBCXX_DEBUG
>     containers in test
>                  implementations.
>
>     Tested under Linux x86_64.
>
>     Ok to commit ?
>
>     PR: https://forge.sourceware.org/gcc/gcc-TEST/pulls/119
>
>     François
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://gcc.gnu.org/pipermail/libstdc++/attachments/20251103/eaa84651/attachment-0001.htm>


More information about the Libstdc++ mailing list