GCC与Clang未遵循new表达式中分配函数的重载解析规则?
GCC/Clang拒绝匹配带align_val_t的operator new的原因分析
先看你的代码示例:
#include <iostream> struct A{ void* operator new(std::size_t N, std::align_val_t){ // #1 return malloc(sizeof(char)* N); } }; int main(){ auto ptr = new A; // #2 }
GCC和Clang的报错信息如下:
<source>:9:17: error: no matching function for call to 'operator new' auto ptr = new A; ^ <source>:4:11: note: candidate function not viable: requires 2 arguments, but 1 was provided void* operator new(std::size_t N, std::align_val_t){ ^ 1 error generated.
你对C++标准[expr.new] p19条款的理解方向是对的,但忽略了两个关键细节:
1. 类成员函数对全局同名函数的隐藏规则
当你在类中定义了任何版本的operator new成员函数时,C++的名称查找规则会直接隐藏全局作用域中所有同名的operator new函数——不管全局函数的参数签名是否和成员函数一致。
所以第一次重载解析时,编译器只会在A的作用域内查找匹配operator new(std::size_t)的函数,但A中只有带两个参数的版本,自然匹配失败。
2. 编译器对二次重载解析规则的实现缺陷
根据标准[expr.new] p19的规定,第一次解析失败后,对于非扩展对齐的对象,应该自动添加std::align_val_t(alignof(A))参数,再次进行重载解析——此时你的operator new(std::size_t, std::align_val_t)完全匹配新的参数列表。
但目前GCC和Clang并没有正确实现这一二次解析逻辑,直接在第一次匹配失败后就抛出错误,这属于编译器的实现缺陷。
验证与绕过方法
如果给A添加扩展对齐(即对齐要求大于平台默认的__STDCPP_DEFAULT_NEW_ALIGNMENT__,通常是8或16字节),比如:
struct alignas(32) A{ void* operator new(std::size_t N, std::align_val_t){ return malloc(sizeof(char)* N); } };
此时编译器会在第一次组装参数列表时就包含align_val_t参数,代码可以正常编译——这也侧面证明标准规则本身是正确的,只是编译器对非扩展对齐场景的二次解析逻辑未实现。
你也可以通过显式引入全局operator new临时绕过,但这不符合你的原本意图:
struct A{ using ::operator new; // 引入全局operator new void* operator new(std::size_t N, std::align_val_t){ return malloc(sizeof(char)* N); } };
内容的提问来源于stack exchange,提问作者xmh0511
相关产品推荐
相关产品推荐

