看来您不仅在做自己的自定义分配器,而且您也不一定要尝试定义与 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);
}