为什么重载 operator new 会改变 new[] 的行为?

Why does overloading operator new change the behavior of new[]?

下面是vs2015下的一段代码运行:

#include<iostream>
using namespace std;
class A {
public:
    A(int _a,int _b){}
    //func1
    void* operator new(size_t sz) {
        cout << "func1"<<endl;
        return malloc(sz);
    }
};
//func2
void* operator new(size_t sz) {
    cout << "func2" << endl;
    return malloc(sz);
}

int main() {
    int* i = new int;//OK,it calls the func2
    int* i1 = new int[6];//why does it call the func2,not the implicit default `operator new[]`?
    A *a = new A(1, 2);//OK,it calls the func1
    A* a1 = new A[2]{ {1,2},{3,4} };//why does it call the func2 instead of func1?
    return 0;
}  

问题:

  1. 我们知道,如果我们想改变new[]的行为,我们只需要定义和替换默认的operator new[]。但是,为什么重载 operator new 也会改变它的行为? 标准是否定义或要求此类行为实现?有什么方法可以阻止它,因为我只想要 new[] 的默认行为?

  2. 根据问题 1,如果重载 operator new 改变了 new[] 的行为,为什么不是 func1,而是 func2new A[2] 语句中调用?


补充:

来自 another code snippet,cppref 评论 int* p2 = new int[10]; // guaranteed to call the replacement in C++11. 似乎 C++11 标准首次保证了这种行为。

Is such behavior implementation defined or required by the standard?

根据[new.delete.array]/4

void* operator new[](std::size_t size);

Default behavior: Returns operator new(size).

通过替换 ::new(std::size_t),您可以 ::new[](std::size_t) 调用您的 custom allocation function。这解释了观察到的行为。


Why isn't func1,but func2 called in new A[2] statement?

似乎 new A[x] 默认行为是调用 ::operator new[],但我不知道为什么。(这是错误的,请参阅 StoryTeller 的回答)。

'operator new' 处理其操作数的大小 - 而不是类型。数组形式的默认实现将所需的大小转发到全局 'operator new'。 'operator new' 只是一个函数,不是模板或任何东西。大小计算中的所有魔法都发生在调用 'operator new' 之前。为了使数组删除成为可能,在数组形式 returns 之后添加了一些小香料。如果在 new/delete 引入 C++ 时出现模板,语义会更加清晰。

我想补充 和地址

Why isn't func1, but func2 called in new A[2] statement?

这一段里都有:

[expr.new]/9

If the new-expression begins with a unary ​::​ operator, the allocation function's name is looked up in the global scope. Otherwise, if the allocated type is a class type T or array thereof, the allocation function's name is looked up in the scope of T. If this lookup fails to find the name, or if the allocated type is not a class type, the allocation function's name is looked up in the global scope.

因此new A[2]将首先在A的范围内寻找合适的分配函数。该函数需要命名为 operator new[]。没有 A::operator new[] 成员,因此查找失败。然后在全局范围内查找该函数。这意味着找到 ::operator new[]。它与分配整数数组的分配函数相同。和 YSC 细节一样,它调用 ::operator new,您将其置换。这就是为什么您观察到 func2 被调用的原因。