Skip to content

[libc++] shrink_to_fit can increase capacity if allocate_at_least returns a bigger allocation #95161

Closed
@MitalAshok

Description

@MitalAshok

https://eel.is/c++draft/vector.capacity#9.sentence-3

constexpr void shrink_to_fit();
Effects: [...] It does not increase capacity(), but may reduce capacity() by causing reallocation.

https://godbolt.org/z/hP63rn661

#include <vector>
#include <memory>
#include <algorithm>

std::size_t min_bytes = 1000;

template<typename T>
struct increasing_allocator {
    using value_type = T;
    increasing_allocator() = default;
    template<typename U>
    constexpr increasing_allocator(const increasing_allocator<U>&) noexcept {}
    std::allocation_result<T*> allocate_at_least(std::size_t n) {
        std::size_t allocation_amount = n * sizeof(T);
        if (allocation_amount < min_bytes) allocation_amount = min_bytes;
        min_bytes += 1000;
        return { static_cast<T*>(::operator new(allocation_amount)), allocation_amount };
    }
    T* allocate(std::size_t n) {
        return allocate_at_least(n).ptr;
    }
    void deallocate(T* p, std::size_t n) noexcept {
        ::operator delete(static_cast<void*>(p));
    }
};

template<typename T, typename U>
constexpr bool operator==(increasing_allocator<T>, increasing_allocator<U>) { return true; }

int main() {
    std::vector<int, increasing_allocator<int>> x;
    x.push_back(1);
    __builtin_printf("Before shrink cap: %zu\n", x.capacity());
    x.shrink_to_fit();
    __builtin_printf("After  shrink cap: %zu\n", x.capacity());
}
Before shrink cap: 1000
After  shrink cap: 2000

The new capacity isn't checked before the elements are moved to the new allocation:

allocator_type& __a = this->__alloc();
__split_buffer<value_type, allocator_type&> __v(size(), size(), __a);
__swap_out_circular_buffer(__v);

This came up when using an arena allocator and the smaller arenas filled up and shrink_to_fit didn't help

Metadata

Metadata

Assignees

Labels

libc++libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions