错误的分配器实现

时间:2011-08-10 22:04:57

标签: c++ visual-studio-2010 c++11

我有一个非常简单的问题。我一直在掀起一个非线程安全的分配器。分配器是一个相当简单的内存竞技场策略 - 分配一个大块,将所有分配放入其中,不做任何解除分配,删除竞技场销毁的全部。但是,实际上尝试使用此方案会引发访问冲突。

static const int MaxMemorySize = 80000;
template <typename T>
class LocalAllocator
{
  public:
      std::vector<char>* memory;
      int* CurrentUsed;
      typedef T value_type;
      typedef value_type * pointer;
      typedef const value_type * const_pointer;
      typedef value_type & reference;
      typedef const value_type & const_reference;
      typedef std::size_t size_type;
      typedef std::size_t difference_type;

    template <typename U> struct rebind { typedef LocalAllocator<U> other; };

    template <typename U>
    LocalAllocator(const LocalAllocator<U>& other) {
        CurrentUsed = other.CurrentUsed;
        memory = other.memory;
    }
    LocalAllocator(std::vector<char>* ptr, int* used) {
        CurrentUsed = used;
        memory = ptr;
    }
    template<typename U> LocalAllocator(LocalAllocator<U>&& other) {
        CurrentUsed = other.CurrentUsed;
        memory = other.memory;
    }
    pointer address(reference r) { return &r; }
    const_pointer address(const_reference s) { return &r; }
    size_type max_size() const { return MaxMemorySize; }
    void construct(pointer ptr, value_type&& t) { new (ptr) T(std::move(t)); }
    void construct(pointer ptr, const value_type & t) { new (ptr) T(t); }
    void destroy(pointer ptr) { static_cast<T*>(ptr)->~T(); }

    bool operator==(const LocalAllocator& other) const { return Memory == other.Memory; }
    bool operator!=(const LocalAllocator&) const { return false; }

    pointer allocate(size_type n) {
        if (*CurrentUsed + (n * sizeof(T)) > MaxMemorySize)
            throw std::bad_alloc();
        auto val = &(*memory)[*CurrentUsed];
        *CurrentUsed += (n * sizeof(T));
        return reinterpret_cast<pointer>(val);
    }
    pointer allocate(size_type n, pointer) {
        return allocate(n);
    }
    void deallocate(pointer ptr, size_type n) {}

    pointer allocate() {
        return allocate(sizeof(T));
    }
    void deallocate(pointer ptr) {}
};

我初始化memory指向一个调整大小到MaxMemorySize的向量,我还初始化了CurrentUsed以指向一个为零的int。我将带有这些值的分配器输入到std::unordered_map的构造函数中,但它一直在STL内部抛出访问冲突。有什么建议吗?

编辑:这是我的用法:

std::vector<char> memory;
int CurrentUsed = 0;
memory.resize(80000);
std::unordered_map<int, int, std::hash<int>, std::equal_to<int>, LocalAllocator<std::pair<const int, int>>> dict(
    std::unordered_map<int, int>().bucket_count(),
    std::hash<int>(),
    std::equal_to<int>(),
    LocalAllocator<std::pair<const int, int>>(&memory, &CurrentUsed)
);
// start timer
QueryPerformanceCounter(&t1);

for (int i=0;i<10000;i++)
    dict[i]=i; // crash

编辑:血淋淋的地狱。当我将大小增加到1MB时它起作用了。我不得不将它增加到超过800,000字节,以使其无需抛弃即可工作。

2 个答案:

答案 0 :(得分:2)

当我测试此代码时,rebind正用于针对同一内存块请求多个分配器。我把

cout << n << " " << sizeof(T) << " " << typeid(T).name() << endl;

在allocate(size_type)的顶部,当我向unordered_map添加了三个元素时:

1 64 struct std::_List_nod<...>
16 4 struct std::_List_iterator<...>
1 64 struct std::_List_nod<...>
1 64 struct std::_List_nod<...>
1 64 struct std::_List_nod<...>

如果您的实现并非巧合地使用了良好的循环64字节请求,则此类将返回错误对齐的分配。

答案 1 :(得分:0)

MSVC10的哈希表类型对于小值类型只有大量的空间开销。它超出了您预留的空间并抛出bad_alloc。

它实现为list<value_t>持有所有元素和散列桶vector<list<value_t>::iterator>,每个元素有2到16个插槽。

每个元素总共有4到18个开销指针。

标准可能需要类似此实现的内容。与vector不同,unordered_map要求元素一旦添加到容器中就不会被移动。