为什么重载 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;
}
问题:
我们知道,如果我们想改变new[]
的行为,我们只需要定义和替换默认的operator new[]
。但是,为什么重载 operator new
也会改变它的行为? 标准是否定义或要求此类行为实现?有什么方法可以阻止它,因为我只想要 new[]
的默认行为?
根据问题 1,如果重载 operator new
改变了 new[]
的行为,为什么不是 func1
,而是 func2
在 new 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?
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?
这一段里都有:
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
被调用的原因。
下面是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;
}
问题:
我们知道,如果我们想改变
new[]
的行为,我们只需要定义和替换默认的operator new[]
。但是,为什么重载operator new
也会改变它的行为? 标准是否定义或要求此类行为实现?有什么方法可以阻止它,因为我只想要new[]
的默认行为?根据问题 1,如果重载
operator new
改变了new[]
的行为,为什么不是func1
,而是func2
在new 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?
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
,butfunc2
called innew A[2]
statement?
似乎 (这是错误的,请参阅 StoryTeller 的回答)。new A[x]
默认行为是调用 ::operator new[]
,但我不知道为什么。
'operator new' 处理其操作数的大小 - 而不是类型。数组形式的默认实现将所需的大小转发到全局 'operator new'。 'operator new' 只是一个函数,不是模板或任何东西。大小计算中的所有魔法都发生在调用 'operator new' 之前。为了使数组删除成为可能,在数组形式 returns 之后添加了一些小香料。如果在 new/delete 引入 C++ 时出现模板,语义会更加清晰。
我想补充
Why isn't
func1
, butfunc2
called innew A[2]
statement?
这一段里都有:
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 typeT
or array thereof, the allocation function's name is looked up in the scope ofT
. 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
被调用的原因。