看来您不仅在做自己的自定义分配器,而且您也不一定要尝试定义与 STL 兼容的分配器。但是,我认为认识到 STL 分配器的所有错误都是为了处理这种情况而设计的。 分配与构造分开:
请注意, [ allocator::construct] 不为元素分配空间,它应该已经可用p(请参阅allocate分配空间的成员)。
它相当于[调用new复制现有对象的放置]。
一般来说,我相信你有两个选择:要么(1)重载operator new来处理分配内存并让系统处理构造,要么(2)让你的分配器接口更像STL分配器接口。
“重载operator new”通常用于表示两件事:(1)替换它,或(2)添加新版本的new. 当我最初回答时,我使用的是第一个含义(实际上应该称为“替换operator new”或“覆盖operator new”);但仔细考虑这一点,我确定真正的重载operator new会满足您的要求。
我应该提到,调用重载的语法operator delete非常糟糕,以至于许多人仅仅因为这个原因而避免使用这种技术。delete您可以创建一个函数(例如deallocate)并使用它,而不是重载。
这种方法的价值在于您遵循将内存分配与对象构造分开的语言标准,并让编译器为您处理对象构造。您不必担心转发运算符,或没有默认构造函数的类,或任何这些问题。
重载operator new/ operator delete(当然,我依靠你来充实track和release):
#include <new>
#include <cstdlib>
struct Allocator {
void track(void* p, const void* container) const;
void release(void* p, const void* container) const;
};
void* operator new (size_t size, const Allocator& alloc, const void* container)
{
void* allocated_memory = std::malloc(size);
if (!allocated_memory) {
throw std::bad_alloc();
}
alloc.track(allocated_memory, container);
return allocated_memory;
}
void operator delete(void* p, const Allocator& alloc, const void* container)
{
alloc.release(p, container);
std::free(p);
}
int main()
{
Allocator alloc;
int* i = new (alloc, NULL) int;
operator delete(i, alloc, NULL);
}
重载operator new和使用函数deallocate:
#include <new>
#include <cstdlib>
struct Allocator {
void track(void* p, const void* container) const;
void release(void* p, const void* container) const;
};
void* operator new (size_t size, const Allocator& alloc, const void* container)
{
void* allocated_memory = std::malloc(size);
if (!allocated_memory) {
throw std::bad_alloc();
}
alloc.track(allocated_memory, container);
return allocated_memory;
}
template<typename T> void deallocate(T* p, const Allocator& alloc, const void* container)
{
p->~T();
alloc.release(p, container);
std::free(p);
}
int main()
{
Allocator alloc;
int* i = new (alloc, NULL) int;
deallocate(i, alloc, NULL);
}
您应该考虑的一种情况是new成功但构造对象失败时该怎么办。也就是说,当有足够的内存,但由于某些其他原因无法创建对象时。系统实际上足够聪明,可以调用权利delete(嗯,delete具有系统认为它应该具有的签名)来释放分配的内存;但前提是有一个delete带有该签名的。您可能很想重载operator delete 并提供一个deallocate函数,其中一个是根据另一个定义的:
void operator delete(void* p, const Allocator& alloc, const void* container)
{
alloc.release(p, container);
std::free(p);
}
template<typename T> void deallocate(T* p, const Allocator& alloc, const void* container)
{
p->~T();
operator delete(p, alloc, container);
}