带大小参数和不带大小参数的`operator delete`:当两者都可用时选择哪一个?

`operator delete` with size parameter and without size parameter: which one is chosen when both are available?

当我在 GCC 和 Clang 中 运行 此代码示例时

struct S
{
  int a;        

  void *operator new(size_t s) 
  { 
    std::cout << "new " << s << std::endl;
    return ::operator new(s); 
  }

  void operator delete(void *p, size_t s) noexcept 
  { 
    std::cout << "delete " << s << std::endl;
    ::operator delete(p);
  }

  void operator delete(void *p) noexcept
  { 
    std::cout << "delete " << "none" << std::endl;
    ::operator delete(p);
  }
};

int main()
{
  S *p = new S;
  delete p;
}

我从 GCC 和 Clang 得到以下输出

new 4
delete none

这意味着编译器选择了 operator delete 的 "sizeless" 版本。

但是,如果我尝试使用全局替换的 operator newoperator delete 函数进行类似操作

struct S
{
  int a;        
};

void *operator new(size_t s)
{
  std::cout << "new " << s << std::endl;
  return std::malloc(s);
}

void operator delete(void *p, size_t s) noexcept
{
  std::cout << "delete " << s << std::endl;
  std::free(p);
}

void operator delete(void *p) noexcept
{
  std::cout << "delete " << "none" << std::endl;
  std::free(p);
}

int main()
{
  S *p = new S;
  delete p;
}

从 GCC 我得到

new 4
delete 4

我从 Clang 得到

new 4
delete none

我知道 "sized" 版本的 in-class operator delete 自 C++98 以来一直存在于 C++ 中,但通过 C++98 看我似乎没有能够找到第一个示例中应选择 operator delete 哪个版本的问题的明确答案。甚至指定了吗?

那么第二个示例中的 C++14 及其 "sized" 版本的全局 operator delete 呢?语言是否说明应该选择哪个版本?

这是 CWG issue 255,可以追溯到 2000 年。引用它的前提:

Paragraph 4 of 15.5 [class.free] speaks of looking up a deallocation function. While it is an error if a placement deallocation function alone is found by this lookup, there seems to be an assumption that a placement deallocation function and a usual deallocation function can both be declared in a given class scope without creating an ambiguity. The normal mechanism by which ambiguity is avoided when functions of the same name are declared in the same scope is overload resolution; however, there is no mention of overload resolution in the description of the lookup. In fact, there appears to be nothing in the current wording that handles this case. That is, the following example appears to be ill-formed, according to the current wording:

struct S {
    void operator delete(void*);
    void operator delete(void*, int);
};
void f(S* p) {
    delete p;    // ill-formed: ambiguous operator delete
}

问题的状态目前为 "drafting",在撰写此答复时,它似乎仍未解决。没有关于释放函数的重载决议的措辞。

Clang 和 GCC 似乎是在任意选择。我认为发出某种关于运算符模棱两可的诊断会更好。