独自のカスタム アロケータを実行しているだけでなく、必ずしも STL 互換のアロケータを定義しようとしているわけでもないようです。ただし、STL アロケーターはすべての障害に対して、このケースを処理するように設計されていることを認識しておくと便利だと思います。 割り当ては構築とは別です:
[ allocator::construct
] は要素にスペースを割り当てないことに注意してください。すでに利用可能になっているはずですp
(スペースを割り当てるメンバーallocate
を参照してください)。
new
[既存のオブジェクトをコピーする配置の呼び出し] に相当します。
一般的に言えば、2 つの選択肢があると思います。(1) オーバーロードoperator new
してメモリの割り当てを処理し、システムに構築を処理させるか、(2) アロケータ インターフェイスを STL アロケータ インターフェイスのようにします。
「オーバーロードoperator new
」は、(1) 置き換える、または (2) の新しいバージョンを追加するという 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);
}
考慮すべきケースの 1 つは、new
成功したもののオブジェクトの作成に失敗した場合の対処方法です。つまり、十分なメモリがあるが、オブジェクトを作成できない他の理由がある場合です。delete
システムは実際には、割り当てられたメモリを解放する権利(delete
システムが持つべきだと考える署名を持つ)を呼び出すのに十分スマートです。delete
ただし、その署名のある がある場合に限ります。関数をオーバーロードoperator delete
して提供し、そのうちの 1 つをもう 1 つの観点から定義したい場合があります。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);
}