gpt4 book ai didi

c++ - operator new[] 的返回地址与数组的实际地址之间的区别

转载 作者:行者123 更新时间:2023-11-30 02:51:58 24 4
gpt4 key购买 nike

最近在玩新的运算符重载。当我重载 new[] 运算符(用于分配数组的 new 运算符)时,我注意到一个奇怪的行为。

这是我的代码:

#include <iostream>
using namespace std;

class Pool
{
public:
void* alloc(size_t size) {
return malloc(size);
}
};

class MyClass
{
public:
MyClass() {
cout<<"ctor called"<<endl;
}
~MyClass() {
cout<<"dtor called"<<endl;
}
void* operator new(size_t size) {
cout<<"new called, size: "<<size<<endl;
return (void*)malloc(size);
}
void* operator new[](size_t size) {
cout<<"new[] called, size: "<<size<<endl;
void* result = (void*)malloc(size);
cout<<"in new[]: "<<result<<endl;
return result;
}
void* operator new(size_t size, void* ptr) {
cout<<"new(ptr) called, size: "<<size<<endl;
return (void*)ptr;
}
void* operator new(size_t size, Pool& pool) {
cout<<"new(Pool) called, size: "<<size<<endl;
return (void*)pool.alloc(size);
}
void operator delete(void* ptr) {
cout<<"delete called, ptr: "<<ptr<<endl;
free(ptr);
}
void operator delete(void* ptr, size_t size) {
cout<<"delete called, ptr: "<<ptr<<", size: "<<size<<endl;
free(ptr);
}
void operator delete[](void* ptr) {
cout<<"delete[] called, ptr: "<<ptr<<endl;
free(ptr);
}
void operator delete[](void* ptr, size_t size) {
cout<<"delete[] called, ptr: "<<ptr<<", size: "<<size<<endl;
free(ptr);
}
uint32_t data;
};

int main() {
Pool pool;
cout<<"Pool"<<endl;
new Pool;
cout<<"MyClass"<<endl;
MyClass *ptr1, *ptr2, *ptr3;
ptr1 = new MyClass;
ptr2 = new MyClass[10]();
cout<<(void*)ptr2<<endl;
ptr3 = new(pool) MyClass;
delete ptr1;
delete[] ptr2;
delete ptr3;

return 0;
}

结果(在 OS X 上使用 gcc 64 位)如下:

Pool
MyClass
new called, size: 4
ctor called
new[] called, size: 48
in new[]: 0x7fa7f0403840
ctor called
ctor called
ctor called
ctor called
ctor called
ctor called
ctor called
ctor called
ctor called
ctor called
0x7fa7f0403848
new(Pool) called, size: 4
ctor called
dtor called
delete called, ptr: 0x7fa7f0403830
dtor called
dtor called
dtor called
dtor called
dtor called
dtor called
dtor called
dtor called
dtor called
dtor called
delete[] called, ptr: 0x7fa7f0403840
dtor called
delete called, ptr: 0x7fa7f0403870

我注意到三件事:第一,我要求在 new[] 中分配 10 个 4 字节的对象,但函数实际收到的请求是 48 字节。第二,显然前 8 个字节用于其他目的:ptr2 接收到的实际地址是 new[] 运算符返回的地址之后的 8 个字节。第三,地址也在重载的 delete[] 函数中自动转换(向前 8 个字节)。

我还注意到只有当我显式实现析构函数时才会发生这种行为。如果我只使用默认的析构函数,那 8 个字节就没有了。

谁能告诉我这背后发生了什么? 8个字节有什么用?

谢谢。

最佳答案

允许 array-new 表达式调用 array-operator-new,使用比数组所需更多的空间。所需要的只是 array-new 表达式的 是指向数组中第一个元素的指针。

实际上,需要额外的空间来存储有关销毁数组时需要销毁多少元素的信息(有时称为“数组 cookie”)。

值得注意的是,从 array-operator-new 函数请求的实际额外内存量是完全不可知的,并且可能会随着每次调用而改变。这基本上使 array-placement-new expression defective and unusable .

仅供引用,相关条款为C++11 5.3.4/10:

A new-expression passes the amount of space requested to the allocation function as the first argument of type std::size_t. That argument shall be no less than the size of the object being created; it may be greater than the size of the object being created only if the object is an array.

最有趣的例子如下:

  • new T[5] results in a call of operator new[](sizeof(T) * 5 + x), and

  • new(2,f) T[5] results in a call of operator new[](sizeof(T) * 5 + y, 2, f).

Here, x and y are non-negative unspecified values representing array allocation overhead; the result of the new-expression will be offset by this amount from the value returned by operator new[]. This overhead may be applied in all array new-expressions, including those referencing the library function operator new[](std::size_t, void*) and other placement allocation functions. The amount of overhead may vary from one invocation of new to another.


您可能会很高兴得知 Itanium ABI对数组 cookie 有非常明智的规则;例如,可简单破坏的对象数组不需要任何东西。

关于c++ - operator new[] 的返回地址与数组的实际地址之间的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19351082/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com