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

自定义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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 06:34:52