如何正确检查指针是否属于分配的块?
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.
一些解决方案可能是:
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.
};
创建一个集合(数组、散列映射、集合...)来跟踪指针。和上面一样的道理(可以比较是否相等),你可以搜索一下这个指针,看看是不是你给出来的。这可能会很慢或内存效率低下。
不要提供传递不是从 new
或 malloc
分配的指针的选项(如果可能)。在问题的集合中,最好提供一个 API 来释放整个桶而不是 API 小片段。这是可行的最佳方案。
在 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)
)来检查指针是否来自桶。然而,所有的桶都来自不同的分配,所以这个比较是不确定的。
如果可能的话,我不想更改界面。我已经 std::less
获得指针类型的严格总顺序,但我无法理解这是否会解决我的问题或只是进行指定的比较。
是否有正确的方法来检查指针是否属于分配的块(以及指针 不 属于块)?
简短的回答是否定的。一个很好的解释是 here.
一些解决方案可能是:
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. };
创建一个集合(数组、散列映射、集合...)来跟踪指针。和上面一样的道理(可以比较是否相等),你可以搜索一下这个指针,看看是不是你给出来的。这可能会很慢或内存效率低下。
不要提供传递不是从
new
或malloc
分配的指针的选项(如果可能)。在问题的集合中,最好提供一个 API 来释放整个桶而不是 API 小片段。这是可行的最佳方案。