コンテキストから始めます-私はメモリ管理サブシステムを作成しており、そのためにnew [] /delete[]演算子の代わりを提供しています。私が解決しなければならなかった問題の1つは、delete []が割り当て解除されたオブジェクトのデストラクタを呼び出すことができるように、new[]によって割り当てられた配列のサイズを格納する方法でした。私が選んだ解決策は、より多くのメモリを割り当て、実際の配列の最初の要素の前に配列のサイズを格納し、その要素へのポインタを返すことでした。私は次のコードを思いついた:
template<typename T, typename AllocatorType>
T* NewArrayHelper(size_t count, AllocatorType* allocator, const char* file, int line) {
// Helper struct
struct Helper {
size_t Count;
T Array[1];
};
Helper* ptr = allocator->Allocate(sizeof(Helper) + sizeof(T)*(count-1), ALIGNOF(Helper), file, line);
// Call constructors, etc. ...
return &ptr->Array[0];
}
このアプローチで私が気に入っているのは、コンパイラが配列とsize_tの正しい配置を判断し、それを読み取ってアロケータに渡す以外に何もする必要がないことです(ALIGNOFはそれを行うマクロです)。また、エイリアシングなどの問題が発生するキャストスルーユニオンやキャストtochar*ハックを行う必要はありません。
一方、delete[]演算子の置き換えに問題があります。つまり、その構造体の内部へのポインタが渡されます。
template<typename T, typename AllocatorType>
void DeleteArrayHelper(T* ptr, AllocatorType* allocator, const char* file, int line) {
// Helper struct
struct Helper {
size_t Count;
T Array[1];
};
// Here ptr points to Array[0] in Helper struct
}
このようなポインターを構造体全体へのポインターに変換する方法を教えてください。ハッキングが最も少なく、移植性が高い可能性があります。