You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义C++ Allocator无法支持swap?shrink_to_fit报错解决

C++自定义分配器调用shrink_to_fit报错问题解决

问题描述

学习C++分配器时,调用std::vector::shrink_to_fit()方法在GCC编译环境下报错,提示std::allocator_traits<MemoryManagerAllocator<int>>::propagate_on_container_swap不存在value成员,但相同代码在MSVC中可正常运行。需要找出自定义分配器缺失的部分并解决该错误。

自定义Allocator代码

#include <cinttypes>
#include <iostream>
#include <algorithm>
#include <vector>
#include <list>
#include <forward_list>
#include <array>
#include <map>

enum class MemoryBank : std::uint8_t
{
    General,
    Audio,
    Video
};

template<std::size_t ChunkSize = 1024>
class ChunkMemoryManager
{
public:
    ChunkMemoryManager() { std::cout << "ChunkMemoryManager()\n"; }
    char* allocate(std::size_t bytes)
    {
        return nullptr;
        /*skipped*/
    }

    void deallocate(char* address, size_t size)
    {
        /*skipped*/
    }

private: // types
    struct Chunk
    {
        Chunk() { freeSlots.emplace_front(0, ChunkSize); }

        std::array<char, ChunkSize>                            memory;
        std::forward_list<std::pair<std::size_t, std::size_t>> freeSlots;
    };

private: // data
    std::list<Chunk> chunks;
};

template<typename T, MemoryBank bank = MemoryBank::General, typename MemoryManager = ChunkMemoryManager<1024>>
class MemoryManagerAllocator
{
public:
    using value_type                  = T;
    using propagate_on_container_swap = std::true_type();
    
    template<typename U>
    struct rebind
    {
        using other = MemoryManagerAllocator<U, bank, MemoryManager>;
    };

    MemoryManagerAllocator()                                             = default;
    MemoryManagerAllocator(const MemoryManagerAllocator&)                = default;
    MemoryManagerAllocator& operator=(const MemoryManagerAllocator& rhs) = default;

    template<class U, MemoryBank UMemoryBank, typename UMemoryManager>
    constexpr MemoryManagerAllocator(const MemoryManagerAllocator<U, UMemoryBank, UMemoryManager>&) noexcept {};

    [[nodiscard]] T* allocate(std::size_t n) { return reinterpret_cast<T*>(memoryManager.allocate(n * sizeof(T))); }

    void deallocate(T* p, std::size_t n) noexcept
    {
        memoryManager.deallocate(reinterpret_cast<char*>(p), n * sizeof(T));
    }

private:
    inline static MemoryManager memoryManager;
};

template<class T, MemoryBank TMemoryBank, class TMemoryManager, class U, MemoryBank UMemoryBank, class UMemoryManager>
bool operator==(const MemoryManagerAllocator<T, TMemoryBank, TMemoryManager>&,
                const MemoryManagerAllocator<U, UMemoryBank, UMemoryManager>&)
{
    return true;
}

template<class T, MemoryBank TMemoryBank, class TMemoryManager, class U, MemoryBank UMemoryBank, class UMemoryManager>
bool operator!=(const MemoryManagerAllocator<T, TMemoryBank, TMemoryManager>&,
                const MemoryManagerAllocator<U, UMemoryBank, UMemoryManager>&)
{
    return false;
}

驱动代码

int main()
{
    using MMAllocator = MemoryManagerAllocator<int>;
    std::vector<int, MMAllocator> v;
    v.shrink_to_fit();
}

编译错误信息

In file included from /usr/include/c++/13/cstdint:38,
                 from /usr/include/c++/13/cinttypes:38,
                 from /home/user/.vs/allocator/src/main.cpp:1:
/usr/include/c++/13/bits/stl_vector.h: In instantiation of ‘constexpr void std::vector<_Tp, _Alloc>::swap(std::vector<_Tp, _Alloc>&) [with _Tp = int; _Alloc = MemoryManagerAllocator<int>]’:
/usr/include/c++/13/bits/alloc_traits.h:908:28:   required from ‘static constexpr bool std::__shrink_to_fit_aux<_Tp, true>::_S_do_it(_Tp&) [with _Tp = std::vector<int, MemoryManagerAllocator<int> >]’
/usr/include/c++/13/bits/vector.tcc:721:56:   required from ‘constexpr bool std::vector<_Tp, _Alloc>::_M_shrink_to_fit() [with _Tp = int; _Alloc = MemoryManagerAllocator<int>]’
/usr/include/c++/13/bits/stl_vector.h:1069:9:   required from ‘constexpr void std::vector<_Tp, _Alloc>::shrink_to_fit() [with _Tp = int; _Alloc = MemoryManagerAllocator<int>]’
/home/user/.vs/allocator/src/main.cpp:143:20:   required from here
/usr/include/c++/13/bits/stl_vector.h:1589:9: error: ‘value’ is not a member of ‘std::allocator_traits<MemoryManagerAllocator<int> >::propagate_on_container_swap’ {aka ‘std::integral_constant<bool, true>()’}
 1589 |         __glibcxx_assert(_Alloc_traits::propagate_on_container_swap::value
      |         ^~~~~~~~~~~~~~~~
gmake[3]: *** [CMakeFiles/allocator.dir/build.make:76: CMakeFiles/allocator.dir/src/main.cpp.o] Error 1

问题原因与解决方案

错误根源

分配器中propagate_on_container_swap的定义错误:你写成了using propagate_on_container_swap = std::true_type();,这是创建了一个临时对象,而非定义类型别名。而C++标准要求,分配器的propagate_on_container_swap必须是一个类型(通常是std::true_type或std::false_type),allocator_traits会访问该类型的静态成员value来判断是否需要在容器swap时传播分配器。

MSVC对该错误兼容性更宽松,允许这种语法,但GCC严格遵循标准,因此报错。

修正方案

将propagate_on_container_swap的定义改为正确的类型别名,去掉括号:

template<typename T, MemoryBank bank = MemoryBank::General, typename MemoryManager = ChunkMemoryManager<1024>>
class MemoryManagerAllocator
{
public:
    using value_type                  = T;
    // 修正:去掉括号,定义为类型别名
    using propagate_on_container_swap = std::true_type;
    
    // 其余代码保持不变...
};

补充说明

如果你的分配器不需要在容器swap时传播(即交换容器时不需要交换分配器实例),可以将其设为std::false_type。但由于你的分配器使用inline static的memoryManager(共享状态),设置为std::true_type是合理的,确保容器swap时分配器状态同步。

内容的提问来源于stack exchange,提问作者qloq

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 02:59:54