简体   繁体   English

为什么重载运算符new会改变new []的行为?

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

Below is a code snippet run under vs2015: 以下是在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;
}  

Questions: 问题:

  1. As we know, if we want to change the behavior of new[] we just need to define and replace the default operator new[] . 众所周知,如果要更改new[]的行为,我们只需定义并替换默认的operator new[] However, why does overloading operator new also change its behavior? 但是,为什么重载operator new也会改变其行为? Is such behavior implementation defined or required by the standard? 该行为实现是否由标准定义或要求? Is there any way to stop that because I just want the default behavior for new[] ? 有什么方法可以阻止这种情况,因为我只想要new[]的默认行为?

  2. Based on question 1, if overloading operator new changes new[] 's behavior, why isn't func1 , but func2 called in new A[2] statement? 基于问题1,如果重载operator new改变了new[]的行为, 为什么func1不是,而是func2new A[2]语句中调用?


supplement: 补充:

From another code snippet , cppref comments int* p2 = new int[10]; // guaranteed to call the replacement in C++11. 另一个代码段中 ,cppref注释int* p2 = new int[10]; // guaranteed to call the replacement in C++11. int* p2 = new int[10]; // guaranteed to call the replacement in C++11. It seems like such behavior is guaranteed in the C++11 standard for the first time. 似乎第一次在C ++ 11标准中保证了这种行为。

I'd like to complement @YSC's answer , and address 我想补充@YSC的答案和地址

Why isn't func1 , but func2 called in new A[2] statement? 为什么不是func1 ,而是func2new A[2]语句中调用?

It's all there in this paragraph: 本段中的所有内容:

[expr.new]/9 [expr.new] / 9

If the new-expression begins with a unary ​::​ operator, the allocation function's name is looked up in the global scope. 如果new表达式以一元运算符​::开头,则在全局范围内查找分配函数的名称。 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 . 否则,如果分配的类型是类类型T或其数组,则在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. 如果此查找找不到名称,或者分配的类型不是类类型,则在全局范围内查找分配函数的名称。

So new A[2] will start by looking for an appropriate allocation function in the scope of A . 因此, new A[2]将首先在A的范围内寻找合适的分配函数。 That function would need to be named operator new[] . 该函数将需要命名为operator new[] There is no A::operator new[] member, so the lookup fails. 没有A::operator new[]成员,因此查找失败。 The function is then looked up in the global scope. 然后在全局范围内查找该功能。 That means ::operator new[] is found. 这意味着找到::operator new[] It's the same allocation function that allocates the array of integers. 这是分配整数数组的相同分配函数。 And like YSC details, it calls ::operator new , which you displaced. 与YSC详细信息一样,它将::operator new替换为您。 That's why you observe func2 being called. 这就是为什么观察到func2被调用的原因。

Is such behavior implementation defined or required by the standard? 该行为实现是否由标准定义或要求?

According to [new.delete.array]/4 : 根据[new.delete.array]/4

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

Default behavior : Returns operator new(size) . 默认行为 :返回operator new(size)

By replacing ::new(std::size_t) , you make ::new[](std::size_t) call your custom allocation function . 通过替换::new(std::size_t) ,可以使::new[](std::size_t)调用自定义分配函数 This explains the observed behaviour. 这解释了观察到的行为。


Why isn't func1 ,but func2 called in new A[2] statement? 为什么不是func1 ,而是func2new A[2]语句中调用?

It seems new A[x] default behaviour is to call ::operator new[] , but I cannot tell why. 似乎new A[x]默认行为是调用::operator new[] ,但我不知道为什么。 (This is wrong, see StoryTeller answer). (这是错误的,请参见StoryTeller的答案)。

'operator new' deals with size -not type- of its operand. “新运算符”处理其操作数的大小(而不是类型)。 The default impl for array form forwards the required size to global 'operator new'. 数组形式的默认impl将所需的大小转发到全局“ operator new”。 'operator new' is just a function, not a template or anything. “新操作员”只是一个功能,而不是模板或其他任何东西。 All the magic in size calculation takes place before call to the 'operator new'. 大小计算中的所有魔术都发生在调用“新操作员”之前。 In order to make array delete possible, some minor spice is added after the array form returns. 为了使删除数组成为可能,在数组形式返回后添加了一些小香料。 Had templates been present when new/delete where introduced to C++, semantics would be much clearer. 如果在将new / delete引入C ++时存在模板,那么语义会更加清晰。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM