我在自己的图书馆工作,我有自己的分配器。我已经声明了一个这样的通用接口:
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 中尝试它时,我遇到了错误:这是因为 msvc2008 编译器被该模板参数愚弄了,所以,当我包含一个使用的标头时正常放置 new [几乎每个 stl 标头都包含对放置 new 的调用,例如 vector、set 等] 编译器将使用我的全局 new 模板版本,而不是放置 new,从而导致明显错误:a type 'void *' 不是类/结构,当然也没有 allocate() 成员函数。
现在,问题出现了:
- 这是msvc2008的bug吗?使用 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 的模板版本似乎不会发生这种情况?