【问题标题】:Bizarre error message in VC12 when attempting to create pool allocator尝试创建池分配器时 VC12 中出现奇怪的错误消息
【发布时间】:2014-08-13 14:26:39
【问题描述】:

我正在尝试创建一个简单的池分配器,它可以与列表和地图等容器一起使用。首先,我有类free_list,它继承自容器使用的节点类型并使用专门的前向链表(所有内存都已分配——分配发生在分配器分配第一项时)给予和收回分配器的allocate 和deallocate 函数中请求的内存。然后我有一个类pool_alloc,它实现了分配器本身并在其分配和释放函数free_list<T>对象类型中返回和接受。

问题子是这样的语句:m_next->give_back(ptr); under pool_alloc::deallocate,它返回 VC12 错误 C2664:它说我无法从类型 'free_list<T>*' 转换为类型 'free_list<free_list<T>>*'。

我不明白为什么free_list<T>::give_back 期望类型free_list<free_list<T>>* 而人们期望它期望free_list<T>*。

有没有办法解决这个问题?

完整的源代码如下:

#include <algorithm>

template<class T>
class free_list : public T {
public:
    free_list* init(std::size_t num_elements) {

        m_next = this;
        free_list* temp = m_next + 1;

        free_list* runner = m_next;
        for (std::size_t s = 1; s < num_elements; ++s) {
            runner->m_next = temp;
            runner = temp;
            temp = runner + 1;
        }
        runner->m_next = nullptr;

        return m_next;
    }

    free_list* obtain() {
        free_list* head = m_next;
        m_next = m_next->m_next;
        return head;
    }

    void give_back(free_list* ptr) {
        ptr->m_next = m_next;
        m_next = ptr;
    }

    free_list* m_next;

};

template<class T>
class pool_alloc {
    typedef pool_alloc<T> myt;

public:
    typedef std::size_t size_type;
    typedef std::ptrdiff_t difference_type;
    typedef free_list<T> value_type;
    typedef T& reference;
    typedef const T& const_reference;
    typedef free_list<T>* pointer;
    typedef const free_list<T>* const_pointer;

    template<class U>
    struct rebind {
        typedef pool_alloc<U> other;
    };

    pool_alloc() : data(nullptr), m_next(nullptr), capacity(4096), allocated(0) {}
    pool_alloc(std::size_t capacity) : data(nullptr), m_next(nullptr), capacity(capacity), allocated(0) {}

    T* address(reference ref) {
        return &ref;
    }

    const T* address(const_reference ref) const {
        return &ref;
    }

    std::size_t max_size() const {
        return capacity;
    }

    pointer allocate(std::size_t) {
        if (allocated >= capacity) throw(std::bad_alloc());
        if (allocated == 0) {
            data = (void*) new char[capacity * sizeof(free_list<T>)];
            m_next = static_cast<free_list<value_type>*>(data);
            m_next->init(capacity);
        }
        return m_next->obtain();
    }

    void deallocate(pointer ptr, std::size_t) {
        m_next->give_back(ptr);
        --allocated;
        if (allocated == 0) {
            delete[](char*)(data);
            data = nullptr;
            m_next = nullptr;
        }
    }

    template<class T, class... Args>
    void construct(T* ptr, Args&&... args) {
        ::new ((void*) ptr) T(std::forward<Args>(args)...);
    }

    template <class T>
    void destroy(T* ptr) {
        ptr->~T();
    }

    bool operator==(const myt& other) {
        return (char)(data) == (char)(other.data);
    }

    bool operator!=(const myt& other) {
        return !operator==(other);
    }

private:

    void* data;
    free_list<value_type>* m_next;
    std::size_t capacity;
    std::size_t allocated;

};

【问题讨论】:

  • 我现在已经用 VS 2012 编译了你的代码,我没有收到那个错误... :-S
  • 错误可能来自使用这段代码的代码,他没有包含。

标签: c++ memory-management


【解决方案1】:

这并不奇怪:您将value_type(错误地)定义为free_list&lt;T&gt; 而不是T,所以m_next 的类型为free_list&lt;free_list&lt;T&gt;&gt;。 pointer 和 const_pointer 有同样的问题。

其他问题:

  • pool_alloc 没有定义正确的复制/移动/赋值操作符。
  • pool_alloc 没有接受 const pool_alloc&lt;U&gt;&amp; 的模板化构造函数,因此您将无法初始化
  • 如果有人试图制作std::vector&lt;T, pool_alloc&lt;T&gt;&gt;,pool_alloc::allocate 将会做出可怕的事情。您可能应该断言参数为 1,或者如果参数大于 1,则回退到 ::operator new(n * sizeof(T))。
  • operator== 和 operator!= 应该是 const。
  • construct 和 destroy 也可以是 const,甚至是 static。
  • 没有必要同时保留data 和m_next,因为它们是相同值的不同类型别名 - 只要您需要data,只需将m_next 转换为void*。
  • 将内存块转储到 deallocate 而不是 ~pool_alloc 可能会导致例如 std::stack&lt;T, std::list&lt;T, pool_alloc&lt;T&gt;&gt; 的异常表现。
  • free_list&lt;T&gt;::init 中的“列表”初始化将每个节点的 m_next 指针指向自身,而不是构建列表。应该是:

    void init(std::size_t num_elements) {
      for (std::size_t i = 0; i < num_elements - 1; ++i) {
          this[i]->m_next = &this[i + 1];
      }
      this[num_elements - 1]->m_next = nullptr;
    }
    

【讨论】:

    猜你喜欢
    • 2023-03-07
    • 2018-06-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多