重载运算符new[]的行为取决于析构函数
Behavior of overloaded operator new[] depends on destructor
以下代码段重载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
,则应该会看到类似的行为。
当你有一个析构函数时,运行库需要知道有多少元素,这样它就可以在销毁数组之前销毁它们。
该标准没有规定应该如何实现这些,但在实际数据之前存储元数据是简单、方便和高效的。
相关文章:
- 什么时候调用组成单元对象的析构函数
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 内联映射初始化的动态atexit析构函数崩溃
- 什么时候调用析构函数
- 优先顺序:智能指针和类析构函数
- C++-明确何时以及如何调用析构函数
- 使用基类指针创建对象时,缺少派生类析构函数
- 在c++中使用向量时,如何调用构造函数和析构函数
- 重载运算符new[]的行为取决于析构函数
- 我需要知道编译器如何在cpp中使用析构函数
- 为什么在使用转换构造函数赋值后调用C++类的析构函数?
- 析构函数调用
- 通过引用传递-为什么要调用这个析构函数
- 对具有动态分配的内存和析构函数的类对象的引用
- 重载 -> shared_ptr 个实例中的箭头运算符<interface>,接口中没有纯虚拟析构函数
- C++成员的析构函数顺序与shared_ptr
- C++ 防止在映射中放置()时调用析构函数
- 在这种情况下显式调用时,std::cout 如何更改析构函数的行为?
- 调用析构函数以释放动态分配的内存
- 没有调用C++析构函数,具体取决于链接顺序