使用重载的普通new运算符进行placement new

12

我有一个MyType类型的对象,由于SSE原因,需要对其进行16字节的对齐。 因此,我编写了一个分配器并重载了new运算符。 MyType中的方法:

inline static void* operator new(size_t size) {
    awesome::my_allocator<MyType,16> alloc;
    return alloc.allocate(size);
}
inline static void* operator new[](size_t size) { return operator new(size); }
inline static void operator delete(void* ptr) {
    awesome::my_allocator<MyType,16> alloc;
    alloc.deallocate(reinterpret_cast<MyType*>(ptr),0); //last arg ignored in my impl
}
inline static void operator delete[](void* ptr) { operator delete(ptr); }

现在,出于缓存本地化的原因,我需要将一个实例复制构造到特定的64字节对齐的内存中:

void MyType::copy_into(uint8_t* ptr) const {
    new (reinterpret_cast<MyType*>(ptr)) MyType(*this);
}

GCC 告诉我:

error: no matching function for call to ‘MyType::operator new(sizetype, MyType*)’

国际刑事法院告诉我:

error : function "MyType::operator new" cannot be called with the given argument list
1>              argument types are: (unsigned __int64, MyType *)
据我理解,放置new运算符由C++实现提供(或可能由<new>提供,我还尝试了 #include),它只是返回其参数(new 使内存可用,并且放置new是程序员表示给定的内存可用)。
有趣的是,当上面定义的(普通的!)new运算符不在类中定义时,该错误就不会发生。事实上,未定义它们的MyOtherType工作得很好。
问题:是什么原因造成这种情况?我应该如何解决它?

也许可以通过重载new函数来传递两个参数 - operator new(size, align),这样普通的、只有一个参数的new函数就不会受到影响。这可能可以绕过编译器的报错,让它使用内置类型。重载抛出异常和不抛出异常的new函数也可能会引起一些问题。 - Michael Dorgan
所有的事情都发生在一个翻译单元中吗? - Lapshin Dmitry
通常情况下,"placement new"被用于"将对象放置在已经分配的内存中",也许你需要重载"placement new"操作符,以便与你的实现相一致。 - AJG85
@AJG85 你无法重载就地构造函数:_"§18.4.1.3 就位构造函数 这些函数已被保留,C++程序不得定义将标准C++库中的版本替换掉的函数。"_ - geometrian
哦,好吧,那个想法就这样了;-( - AJG85
附带说明:copy_into() 可以检查给定的内存是否为 16 字节对齐。遗憾的是它无法检查给定的内存是否足够大。 - Jerry101
1个回答

10

由于您在类中定义了operator new,因此您需要使用全局的new来使用其放置版本。

#include <new>

...

::new (reinterpret_cast<MyType*>(ptr)) MyType(*this);

确认这解决了问题。据我所知,当前命名空间中有过多的 new,因此它没有检查全局命名空间以找到可用的重载(放置 new)。 - geometrian
我不会说“在当前命名空间中”。我会说“在class本身中”。匹配函数调用涉及两个步骤 - 名称查找和重载解析。如果在类或封闭命名空间中找到名称,则查找结束。如果查找结果有多个函数,则才会进行重载解析。 - R Sahu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接