自定义allocator用于std::unordered_map触发类型匹配断言错误
问题:自定义TLSF分配器在std::unordered_map中触发静态断言错误
错误信息
/usr/include/c++/11/bits/hashtable.h:204:21: error: static assertion failed: unordered container must have the same value_type as its allocator 204 | static_assert(is_same<typename _Alloc::value_type, _Value>{},
场景代码
类a的定义
class a { public: [[nodiscard]] static std::shared_ptr<a> create(); template<typename T, typename... Args> T* create_b(Args&&... args) { std::unique_ptr<T> b = std::make_unique<T>(std::forward<Args>(args)...); Bs_.push_back(std::move(b)); return static_cast<T*>(Bs_.back().get()); } void* operator new(std::size_t size) { tlsf_allocator allocator; return allocator.allocate<a>(size); } void operator delete(void* ptr) { tlsf_allocator allocator; allocator.deallocate<a>(static_cast<a*>(ptr), 1); } private: a(); // 正常工作但未使用自定义分配器的版本 // std::unordered_map<const i_b*, c*, std::hash<const i_b*>, std::equal_to<const i_b*>> Bs_to_Cs_{}; // 触发错误的版本 std::unordered_map<const i_b*, c*, std::hash<const i_b*>, std::equal_to<const i_b*>, tlsf_allocator::allocator_for<std::pair<const i_b*, c*>>> Bs_to_Cs_{}; // 正常工作的vector+自定义分配器 std::vector<std::unique_ptr<i_b>, tlsf_allocator::allocator_for<std::unique_ptr<i_b>>> Bs_{}; };
自定义TLSF分配器实现
class tlsf_allocator { public: template<typename T> T* allocate(size_t n) { T* result = reinterpret_cast<T*>(tlsf_malloc(get_tlsf_pool(), sizeof(T) * n)); if (result == nullptr) { throw std::bad_alloc(); } return result; } template<typename T> void deallocate(T* ptr, [[maybe_unused]] size_t n) { tlsf_free(get_tlsf_pool(), ptr); } template<typename U> struct allocator_for { using value_type = U; allocator_for() noexcept = default; template<typename V> explicit allocator_for([[maybe_unused]] const allocator_for<V>& other) noexcept {} U* allocate(std::size_t n) { tlsf_allocator allocator; return reinterpret_cast<U*>(allocator.allocate<U>(n)); } void deallocate(U* p, std::size_t n) noexcept { tlsf_allocator allocator; allocator.deallocate<U>(p, n); } }; private: static tlsf_t& get_tlsf_pool(); };
问题原因
std::unordered_map的底层哈希表实现需要分配哈希节点对象(而非仅用户指定的std::pair<const K,V>),此时容器会通过分配器的rebind机制获取对应节点类型的分配器。你的allocator_for结构体没有实现rebind,导致std::allocator_traits无法正确推导所需的分配器类型,最终触发容器对value_type一致性的静态断言检查。
而std::vector仅需分配用户指定的元素类型内存,不需要rebind其他类型,因此可以正常工作。
解决方案
修改allocator_for结构体,添加rebind支持,同时移除多余的类型转换:
template<typename U> struct allocator_for { using value_type = U; allocator_for() noexcept = default; template<typename V> explicit allocator_for([[maybe_unused]] const allocator_for<V>& other) noexcept {} U* allocate(std::size_t n) { tlsf_allocator allocator; return allocator.allocate<U>(n); // 无需reinterpret_cast,allocate已返回U* } void deallocate(U* p, std::size_t n) noexcept { tlsf_allocator allocator; allocator.deallocate<U>(p, n); } // 添加rebind机制,满足STL容器的分配器要求 template<typename V> struct rebind { using other = allocator_for<V>; }; };
修改后,std::unordered_map可以通过rebind获取哈希节点类型的分配器,静态断言即可通过。
内容的提问来源于stack exchange,提问作者Jager
相关产品推荐
相关产品推荐

