Handle allocator propagation in basic_memory_buffer::move

Update `basic_memory_buffer::move` to respect `propagate_on_container_move_assignment`allocator trait.
If the allocator should not propagate and differs from the target's allocator,
fallback to copying the buffer instead of transferring ownership.

This avoids potential allocator mismatch issues and ensures exception safety.
This commit is contained in:
Murat Toprak 2025-07-08 13:44:08 +03:00
parent 93f03953af
commit 5deae85b18
2 changed files with 31 additions and 1 deletions

View File

@ -751,6 +751,14 @@ template <typename T> struct allocator : private std::decay<void> {
}
void deallocate(T* p, size_t) { std::free(p); }
friend bool operator==(const allocator&, const allocator&) noexcept {
return true; // All instances of this allocator are equivalent.
}
friend bool operator!=(const allocator& a, const allocator& b) noexcept {
return !(a == b);
}
};
} // namespace detail
@ -828,9 +836,20 @@ class basic_memory_buffer : public detail::buffer<T> {
private:
// Move data from other to this buffer.
FMT_CONSTEXPR20 void move(basic_memory_buffer& other) {
alloc_ = std::move(other.alloc_);
using alloc_traits = std::allocator_traits<Allocator>;
T* data = other.data();
size_t size = other.size(), capacity = other.capacity();
if constexpr (alloc_traits::propagate_on_container_move_assignment::value) {
alloc_ = std::move(other.alloc_);
} else {
if (alloc_ != other.alloc_) {
this->reserve(capacity);
detail::copy<T>(data, data + size, this->data());
this->resize(size);
return;
}
}
if (data == other.store_) {
this->set(store_, capacity);
detail::copy<T>(other.store_, other.store_ + size, store_);

View File

@ -72,6 +72,17 @@ template <typename Allocator> class allocator_ref {
return std::allocator_traits<Allocator>::allocate(*alloc_, n);
}
void deallocate(value_type* p, size_t n) { alloc_->deallocate(p, n); }
friend bool operator==(const allocator_ref& a, const allocator_ref& b) noexcept {
if (a.alloc_ == b.alloc_) return true;
if (a.alloc_ == nullptr || b.alloc_ == nullptr) return false;
return *a.alloc_ == *b.alloc_;
}
friend bool operator!=(const allocator_ref& a, const allocator_ref& b) noexcept {
return !(a == b);
}
};
#endif // FMT_MOCK_ALLOCATOR_H_