在下面的C类对象创建过程中观察到不同大小的内存分配,
class C {
int i;
int j;
};
void f() {
C *c = new C;
C *c2 = new C[2];
C (*c3)[2] = new C[2][2];
}
c分配8个字节;
c2分配8 * 2 + 4字节;
c3分配有8 * 2 * 2 + 4个字节。
为什么c2和c3再获取4个字节?
答案 0 :(得分:8)
请记住,C ++会分离内存分配和对象表达式。默认的数组新表达式T * p = new T[N];
都为N
个对象分配足够的内存和构造这些对象。在另一端,delete[] p;
必须调用所有这些元素的析构函数,然后释放内存。
虽然平台处理分配和释放存储器,并且通过单个指针值足够清楚地识别可用存储器,但构造和销毁对象更复杂。实际对象的数量必须存储在某处,为此,标准允许C ++实现请求比N * sizeof(T)
更多的内存。确实,指针p
将始终指向N
对象数组的开头,但p
不必与底层内存分配器返回的指针相同。 (事实上,p
保证恰好是基础分配结果的值,超出内存量。)
细节完全取决于实施。但是,有些平台提供了额外的保证;例如,Itanium ABI(调用额外数据“数组cookie”)表示new T[N]
的内存将按如下方式排列:
+- alignof(T) --+-- sizeof(T) --+-- sizeof(T) --+-- sizeof(T) --+-- ...
| ***** [8B: N] | 1st element | 2nd element | 3rd element | .....
+---------------+---------------+---------------+---------------+-- ...
A A
| |_ result of "new T[N]"
|
|_ value returned "operator new[]()"
答案 1 :(得分:4)
来自标准([expr.mew]
部分):
new-expression 将请求的空间量作为
std::size_t
类型的第一个参数传递给分配函数。该参数不得小于正在创建的对象的大小;仅当对象是数组时,它可能大于正在创建的对象的大小。
显然,该标准期望一些附加信息与动态分配的数组一起存储。
现在,使用调试器查看填充到这些额外字节中的内容,并找出编译器执行其工作可能需要多少额外信息。
(提示:修复程序,使其不会泄漏内存)
答案 2 :(得分:3)
许多编译器在从new []返回指针之前使用4个字节来存储实际分配的对象数。这是所有依赖于实现的,重要的是要记住指针算法超出您分配的内存范围会导致未定义的行为