[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