[libcxx-commits] [libcxx] [libc++] Add __uninitialized_allocator_{fill, value_construct, move} and use them in vector (PR #207500)
Louis Dionne via libcxx-commits
libcxx-commits at lists.llvm.org
Wed Jul 22 07:52:01 PDT 2026
https://github.com/ldionne updated https://github.com/llvm/llvm-project/pull/207500
>From 9dde19ee8b7ad4dce0f74550288727526285fdfb Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Sat, 4 Jul 2026 11:06:55 +0200
Subject: [PATCH] [libc++] Add
__uninitialized_allocator_{fill,value_construct,move} and use them in vector
---
libcxx/docs/ReleaseNotes/23.rst | 3 ++
.../__memory/uninitialized_algorithms.h | 38 +++++++++++++++++++
libcxx/include/__vector/vector.h | 14 ++-----
.../sequences/vector/asan_throw.pass.cpp | 2 +-
4 files changed, 45 insertions(+), 12 deletions(-)
diff --git a/libcxx/docs/ReleaseNotes/23.rst b/libcxx/docs/ReleaseNotes/23.rst
index f7a8e5b04f1ea..27c68b93506ce 100644
--- a/libcxx/docs/ReleaseNotes/23.rst
+++ b/libcxx/docs/ReleaseNotes/23.rst
@@ -101,6 +101,9 @@ Potentially breaking changes
- ``std::exception_ptr`` on Windows no longer relies on STL and is now implemented entirely within libc++.
The implementation was donated by Microsoft and has been refactored to follow libc++ standards and conventions.
+- The destruction order as well as whether elements are destructed in ``vector`` when appending has changed.
+ Specifically, when an exception is thrown, the appended elements are now destructed from first to last.
+
Announcements About Future Releases
-----------------------------------
diff --git a/libcxx/include/__memory/uninitialized_algorithms.h b/libcxx/include/__memory/uninitialized_algorithms.h
index f184b2b9dd925..baca90fb10554 100644
--- a/libcxx/include/__memory/uninitialized_algorithms.h
+++ b/libcxx/include/__memory/uninitialized_algorithms.h
@@ -302,6 +302,30 @@ uninitialized_move_n(_InputIterator __ifirst, _Size __n, _ForwardIterator __ofir
#endif // _LIBCPP_STD_VER >= 17
+template <class _Alloc, class _Iter, class _Sent, class _Tp>
+_LIBCPP_CONSTEXPR_SINCE_CXX20
+_Iter __uninitialized_allocator_fill(_Alloc& __alloc, _Iter __first, _Sent __last, const _Tp& __value) {
+ auto __iter = __first;
+
+ auto __guard = std::__make_exception_guard([&] { std::__allocator_destroy(__alloc, __first, __iter); });
+ for (; __iter != __last; ++__iter)
+ allocator_traits<_Alloc>::construct(__alloc, std::__to_address(__iter), __value);
+ __guard.__complete();
+ return __iter;
+}
+
+template <class _Alloc, class _Iter, class _Sent>
+_LIBCPP_CONSTEXPR_SINCE_CXX20
+_Iter __uninitialized_allocator_value_construct(_Alloc& __alloc, _Iter __first, _Sent __last) {
+ auto __iter = __first;
+
+ auto __guard = std::__make_exception_guard([&] { std::__allocator_destroy(__alloc, __first, __iter); });
+ for (; __iter != __last; ++__iter)
+ allocator_traits<_Alloc>::construct(__alloc, std::__to_address(__iter));
+ __guard.__complete();
+ return __iter;
+}
+
template <class _Alloc, class _Iter>
class _AllocatorDestroyRangeReverse {
public:
@@ -380,6 +404,20 @@ inline const bool __allocator_has_trivial_move_construct_v = !__has_construct_v<
template <class _Type>
inline const bool __allocator_has_trivial_move_construct_v<allocator<_Type>, _Type> = true;
+template <class _Alloc, class _InIter, class _Sent, class _OutIter>
+_LIBCPP_CONSTEXPR_SINCE_CXX20 __in_out_result<_InIter, _OutIter>
+__uninitialized_allocator_move(_Alloc& __alloc, _InIter __first, _Sent __last, _OutIter __result) {
+ auto __destruct_first = __result;
+ auto __guard = std::__make_exception_guard([&] { std::__allocator_destroy(__alloc, __destruct_first, __result); });
+ while (__first != __last) {
+ allocator_traits<_Alloc>::construct(__alloc, std::__to_address(__result), std::move(*__first));
+ ++__first;
+ ++__result;
+ }
+ __guard.__complete();
+ return {std::move(__first), std::move(__result)};
+}
+
template <class _Alloc, class _Tp>
inline const bool __allocator_has_trivial_destroy_v = !__has_destroy_v<_Alloc, _Tp*>;
diff --git a/libcxx/include/__vector/vector.h b/libcxx/include/__vector/vector.h
index 8226a7f87a119..6f700440ae321 100644
--- a/libcxx/include/__vector/vector.h
+++ b/libcxx/include/__vector/vector.h
@@ -878,10 +878,7 @@ vector<_Tp, _Allocator>::__recommend(size_type __new_size) const {
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::__construct_at_end(size_type __n) {
_ConstructTransaction __tx(*this, __n);
- const_pointer __new_end = __tx.__new_end_;
- for (pointer __pos = __tx.__pos_; __pos != __new_end; __tx.__pos_ = ++__pos) {
- __alloc_traits::construct(this->__layout_.__alloc(), std::__to_address(__pos));
- }
+ __tx.__pos_ = std::__uninitialized_allocator_value_construct(__layout_.__alloc(), __tx.__pos_, __tx.__new_end_);
}
// Copy constructs __n objects starting at __layout_.__end_ptr() from __x
@@ -894,10 +891,7 @@ template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 inline void
vector<_Tp, _Allocator>::__construct_at_end(size_type __n, const_reference __x) {
_ConstructTransaction __tx(*this, __n);
- const_pointer __new_end = __tx.__new_end_;
- for (pointer __pos = __tx.__pos_; __pos != __new_end; __tx.__pos_ = ++__pos) {
- __alloc_traits::construct(this->__layout_.__alloc(), std::__to_address(__pos), __x);
- }
+ __tx.__pos_ = std::__uninitialized_allocator_fill(__layout_.__alloc(), __tx.__pos_, __tx.__new_end_, __x);
}
template <class _Tp, class _Allocator>
@@ -1121,9 +1115,7 @@ vector<_Tp, _Allocator>::__move_range(pointer __from_s, pointer __from_e, pointe
{
pointer __i = __from_s + __n;
_ConstructTransaction __tx(*this, __from_e - __i);
- for (pointer __pos = __tx.__pos_; __i < __from_e; ++__i, (void)++__pos, __tx.__pos_ = __pos) {
- __alloc_traits::construct(this->__layout_.__alloc(), std::__to_address(__pos), std::move(*__i));
- }
+ __tx.__pos_ = std::__uninitialized_allocator_move(__layout_.__alloc(), __i, __from_e, __tx.__pos_).__out_;
}
std::move_backward(__from_s, __from_s + __n, __old_last);
}
diff --git a/libcxx/test/libcxx/containers/sequences/vector/asan_throw.pass.cpp b/libcxx/test/libcxx/containers/sequences/vector/asan_throw.pass.cpp
index dcfa8029cfc0d..5089cd716266a 100644
--- a/libcxx/test/libcxx/containers/sequences/vector/asan_throw.pass.cpp
+++ b/libcxx/test/libcxx/containers/sequences/vector/asan_throw.pass.cpp
@@ -182,7 +182,7 @@ void test_insert_n2() {
v.insert(v.cbegin(), 5, ThrowOnCopy());
assert(0);
} catch (int e) {
- assert(v.size() == 11);
+ assert(v.size() == 10);
assert(is_contiguous_container_asan_correct(v));
return;
}
More information about the libcxx-commits
mailing list