【问题标题】:Why does overloading operator new change the behavior of new[]?为什么重载 operator new 会改变 new[] 的行为?
【发布时间】:2018-04-23 11:20:55
【问题描述】:

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

#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[]的行为,为什么new A[2]语句中没有调用func1,而是func2


补充:

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

【问题讨论】:

  • IIRC在全局范围内,::new[]是从::new定义的,所以...
  • 是的,查看en.cppreference.com/w/cpp/memory/new/operator_new 中的条目(2):“标准库实现调用版本(1)”
  • @YSC 那么它的实现是标准定义的还是要求的?
  • 我猜是前者。
  • @YSC 来自linkage 中的一个代码 sn-p,cppref cmets int* p2 = new int[10]; // guaranteed to call the replacement in C++11。从标准 c++11 开始,这种行为似乎得到了保证。

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


【解决方案1】:

我想补充一下@YSC's answer,以及地址

为什么new A[2] 语句中没有调用func1,而是func2

这一段都在里面:

[expr.new]/9

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

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

【讨论】:

    【解决方案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。这解释了观察到的行为。


    为什么在new A[2] 语句中没有调用func1,而是func2

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

    【讨论】:

    • 但是为什么不调用A::operator new?标准是否规定默认::operator new[]必须调用::operator new,但不是最合适的?
    • 不,这是在new A[2] 语句中调用的func2
    • @bigxiao 我不知道 :(
    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 2011-08-30
      • 1970-01-01
      • 1970-01-01
      • 2011-01-11
      • 2021-08-31
      • 1970-01-01
      • 1970-01-01
      • 2012-01-05
      • 2011-03-25
      相关资源
      最近更新 更多