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

问题描述

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

constructor(public fireStore: AngularFirestore) { }

SetUserData(user) {
   const userData: User = {
      uid: user.uid,email: user.email,displayName: user.displayName,photoURL: user.photoURL,emailVerified: user.emailVerified,admin: user.admin == false
    }
    if(user.email === "master@mail.com") {
      this.fireStore.doc('users/' + userData.uid).update(userData);
      console.log(user.admin)
    }
 }

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)来检查指针是否来自存储桶。然而,所有的桶都来自不同的分配,所以这个比较是未指定的。

如果可能,我不想更改界面。我有 also read 可以使用 std::less 来获得指针类型的严格总顺序,但我无法理解这是否会解决我的问题或只是使比较指定。

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

解决方法

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

一些变通的解决方案可能是:

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

     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。这是可行的最佳解决方案。