重载运算符new[]的行为取决于析构函数

Behavior of overloaded operator new[] depends on destructor

本文关键字:取决于 析构函数 运算符 new 重载      更新时间:2023-10-16

以下代码段重载operator new[]并打印出所需的size和指针地址

class MyClass
{
private:
int _data;    //sizeof(MyClass) == 4
public:
void* operator new[](size_t size)
{
cout << "MyClass::operator new[]" << endl;
cout << "size = " << size << endl;
void* p = malloc(size);
cout << "p = " << p << endl;
return p;
}
};
int main()
{
MyClass* a = new MyClass[100];
cout << "a = " << a << endl;
}

输出

>>  MyClass::operator new[]
>>  size = 400
>>  p = 0x55e335a3f280
>>  a = 0x55e335a3f280

但是,通过显式添加/定义析构函数

class MyClass
{
...
public:
...
~MyClass() {}
};
int main()
{
MyClass* a = new MyClass[100];
cout << "a = " << a << endl;
}

结果改变了

>>  MyClass::operator new[]
>>  size = 408
>>  p = 0x564f30cd7280
>>  a = 0x564f30cd7288

这意味着表达式CCD_ 3正在请求来自CCD_。额外的内存字节似乎存储了数组的大小,甚至可以访问!

cout << "info: " << *(reinterpret_cast<size_t*>(a) - 1) << endl;

结果

>>  info: 100

我的问题是谁和为什么要使用这8字节的信息?这是标准的一部分吗?如果是的话,有没有解释为什么它被设计成这样的行为?

未指定调用任何数组new时是否存在开销以及开销有多少。这种行为完全在对编纂者的宽大处理范围内。额外的空间通常用于指示阵列中有多少元素。

在调用delete[]时,需要调用每个元素的析构函数;只有当我们知道有多少元素时,才能做到这一点。在元素具有琐碎析构函数的情况下,不需要调用任何析构函数,因此不需要空间。

请注意,尽管实现通常在operator delete中委托std::free,但这并不能保证,您也应该重载operator delete

如果您不使用析构函数,而是添加了一个具有非平凡析构函数的成员,如std::string,则应该会看到类似的行为。

当你有一个析构函数时,运行库需要知道有多少元素,这样它就可以在销毁数组之前销毁它们。

该标准没有规定应该如何实现这些,但在实际数据之前存储元数据是简单、方便和高效的。