如何正确检查指针是否属于分配的块?

How to correcly check whether a pointer belongs within an allocated block?

reading many questions 指针比较之后,我开始意识到我的许多自定义分配器都进行了未指定行为的比较。一个例子可能是这样的:

template <int N, int CAPACITY>
class BucketList
{
    struct Bucket
    {
        Bucket* next { nullptr };      // The next bucket, to create a linked list.
        size_t  size { 0 };            // Size allocated by the bucket.
        uint8_t data[CAPACITY] { 0 };
    };

    Bucket* free;  // The first bucket that has free space.
    Bucket* next;  // The next bucket, to create a linked list.

public:
    BucketList()
    {
        this->next = new Bucket;
        this->free = this->next;
    }

    uint8_t* allocate()
    {
        auto* bucket = this->free;

        if (bucket->used + N >= CAPACITY)
        {
            bucket->next = new Bucket;
            this->free   = bucket->next;
            bucket       = bucket->next;
        }

        uint8_t* base = bucket->data + bucket->used;
        bucket->used_size += N;
        return base;
    }

    uint8_t* deallocate(uint8_t* ptr)
    {
        auto* bucket = this->next;
        while (bucket && !(bucket->data <= ptr && ptr < bucket->data + CAPACITY))
            bucket = bucket->next;
        
        if (bucket)
            // Bucket found! Continue freeing the object and reorder elements.
        else
            // Not allocated from here. Panic!
    }

    // And other methods like destructor, copy/move assignment, and more...
};

allocate函数returns从分配的数组中提取一小块数据。为了释放,它通过检查指针的地址是否在桶的地址范围内(即 (bucket->data <= ptr && ptr < bucket->data + CAPACITY))来检查指针是否来自桶。然而,所有的桶都来自不同的分配,所以这个比较是不确定的。

如果可能的话,我不想更改界面。我已经 read that it's possible to use std::less 获得指针类型的严格总顺序,但我无法理解这是否会解决我的问题或只是进行指定的比较。

是否有正确的方法来检查指针是否属于分配的块(以及指针 属于块)?

简短的回答是否定的。一个很好的解释是 here.

一些解决方案可能是:

  1. Return 一个自定义对象,它引用了分配的基指针。由于相等比较不是未指定的,因此您应该能够将它与集合的基指针进行比较。为了方便起见,自定义对象也可以实现指针的接口。类似于:

     class Pointer
     {
         uint8_t* base;
         size_t   offset;
    
     public:
         // Dereference operator.
         uint8_t operator*() { return this->base[offset]; }
    
         // Implement the methods and operators required for 
         // your use case.
     };
    
  2. 创建一个集合(数组、散列映射、集合...)来跟踪指针。和上面一样的道理(可以比较是否相等),你可以搜索一下这个指针,看看是不是你给出来的。这可能会很慢或内存效率低下。

  3. 不要提供传递不是从 newmalloc 分配的指针的选项(如果可能)。在问题的集合中,最好提供一个 API 来释放整个桶而不是 API 小片段。这是可行的最佳方案。