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

时间:2018-04-23 11:20:56

标签: c++ operator-overloading language-lawyer new-operator

以下是在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,而是{{1在func2声明中调用?

  3. 的补充:

    来自another code snippet,cppref评论new A[2]这种行为似乎首次在C ++ 11标准中得到保证。

3 个答案:

答案 0 :(得分:5)

我想补充@YSC's answer和地址

  

为什么不是func1,而func2new A[2]声明中被调用?

这一段都在那里:

  

[expr.new]/9

     

如果 new-expression 以一元​::运算符开头,那么   在全局范围内查找分配函数的名称。   否则,如果分配的类型是类类型T或其数组,   在T的范围内查找分配函数的名称。如果这   查找无法找到名称,或者分配的类型不是类   在类型中,分配函数的名称在全局范围内查找。

所以new A[2]将首先在A的范围内寻找合适的分配函数。该函数需要命名为operator new[]。没有A::operator new[]成员,因此查找失败。然后在全局范围中查找该函数。这意味着找到了::operator new[]。它是分配整数数组的相同分配函数。和YSC的详细信息一样,它会调用你移位的::operator new。这就是你观察func2被召唤的原因。

答案 1 :(得分:2)

  

标准是否定义或要求此类行为实施?

根据[new.delete.array]/4

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

默认行为:返回operator new(size)

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

  

为什么不是func1,而是在func2声明中调用new A[2]

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

答案 2 :(得分:-1)

&#39; operator new&#39;处理其操作数的大小-not type-。数组表单的默认impl将所需大小转发给全局&#39; operator new&#39;。 &#39; operator new&#39;只是一个功能,而不是模板或任何东西。所有神奇的大小计算都是在调用&#39;运算符new&#39;之前进行的。为了使数组删除成为可能,在数组表单返回后添加一些次要的spice。如果在引入C ++的新/删除时模板已存在,语义将更加清晰。