私は自分の図書館で働いていて、自分のアロケーターを持っています。次のような共通インターフェイスを宣言しました。
class MyAllocator
{
public:
void * allocate(size_t size);
void * allocate(size_t size, size_t align);
void deallocate(void *);
//...
};
ここで、C++ オブジェクトをこのようなアロケーターで割り当てたい場合は、配置 new を次のように使用する必要があります。
MyAllocator a;
MyObject * o = new(a.allocate(sizeof(MyObject))) MyObject(param1, param2, ...);
もちろん、これはかなりうまく機能します。さて、先ほど sizeof() の繰り返しを避けるために、アロケーターをパラメーターとして受け取るグローバル アロケーターを作成したいと考えました。だから私はこれで来ます:
template< typename AllocatorT >
inline
void *operator new(size_t n_bytes, AllocatorT & allocator)
{
return allocator.allocate(n_bytes);
}
これで、私はただ呼び出すことができます:
MyAllocator my_alloc;
MyObject * o = new(my_alloc) MyObject(param1, param2);
構文は非常にクリーンでクールです。これも基本的に (gcc と msvc2010 で) うまく機能しますが、今日、msvc2008 で試してみるとエラーが発生しました。通常の配置 new [ほとんどすべての stl ヘッダーには配置 new への呼び出しが含まれています。たとえば、vector、set など] コンパイラは配置 new の代わりにグローバル new のテンプレート化されたバージョンを使用し、明らかなエラーを引き起こします: type 'void *' はクラス/構造体ではなく、もちろん allocate() メンバー関数はありません。
ここで、次のような疑問が生じます。
- これは msvc2008 のバグですか? gcc 4.4.0、4.4.5、および msvc2010 では、かなりうまく機能します。
- アロケータ参照を受け入れるテンプレート化されたグローバル new 演算子を書くのは間違っていますか? つまり、これはコンパイラーをだまされやすく、しばしばエラーを引き起こす可能性のあるあいまいな構文である可能性がありますか? 前述のように、通常の配置 new を使用するカスタム アロケータを使用すると、C++ オブジェクトの割り当ての複雑さが大幅に軽減されます。
通常、次の場合:
ボイド f(ボイド *); //1 テンプレート< typename A >f(A &); //2
そして、次を呼び出します。
void * void_ptr = something();
f(void_ptr);
もちろん、ここで最初のバージョンが呼び出されます。
なぜこれは msvc2008 でそのテンプレート化されたバージョンの operator new で発生しないように見えるのですか?