2

我想知道为什么在下面的代码中指针aptr和amemTab之间的差异不等于分配数组的大小(10 * sizeof(A))而是64字节(sizeof(A)是4)。

在调试模式下:

aptr 0x00395e38

amemTab 0x00395e78

Win XP 家庭版,MSVS2010,x86 Intel 1.86

我想这与填充有关?(我没有删除基类和派生类的代码,因为我想准确地展示我正在测试的内容,但这里是多余的,我只说两行:

A * aptr=static_cast<A*>(amem);
void * amemTab= operator new[](10*sizeof(A));

我的完整示例:

// exercise
//

#include "stdafx.h"
#include <algorithm>

void func(const int &i){printf("%d\n",i);}

class A{
public:
    int i;
};
class B{
public:
    int i;
private:
    int j;
};
class base{
public: 
    void f(void){printf("base f not virtual\n");}
    virtual void g(void){printf("base g virtual\n");}
    void h(void){printf("base h not virtual\n\n");}
    int i_;
    base():i_(123){}
    base(int):i_(12345){}
};
class derived:public base{
public: 
    void f(void){printf("derived f not virtual\n");}
    virtual void g(void){printf("derived g virtual\n");}
};

int _tmain(int argc, _TCHAR* argv[])
{
    int ij;
    A a;/*a.i is not initialized*/
    A * aprimprim=new A;/*i is not initialized (but ctor has been called)*/
    A aprim=A();/*aprim.i is 0 initialized as it is public variable 
                and A has only public part (A is POD type) and () is written*/
    A * ap=new A();/*int is 0 initialized*/
    B b;/*b.i is not initialized and b.j is not initialized*/
    B bprim=B();/*bprim.i is not initialized and bprim.j is not initialized
                as A has public AND also private part*/
    B * bp=new B();/*ints are both 0 initialized*/

    void * amem= operator new (sizeof(A));/*uninitialized memory, only allocate*/
    A * aptr=static_cast<A*>(amem);//cast pointer to void to pointer to A

    void * amemTab= operator new[](10*sizeof(A));/*uninitialized memory, only 
                                            allocate for 10 objects of A size*/
    A * aptrtab=static_cast<A*>(amemTab);/*cast pointer to void to pointer to 
                                         A. now it is possible to iterate through
                                         this area of indexed memory:*/
    for(int i=0;i<10;i++){
        new(&aptrtab[i])A();//initialize each A object 
    }
    int s=sizeof(A);
    /*------------------------------*/
    int myarray[5];/*ints are uninitialized*/
    *(1+myarray)=13;/*pointer addition is commutative*/
    2[myarray]=4;/*subscript operator is commutative*/

    std::for_each(myarray,myarray+5,func);

    /*---------------*/
    int *what_here=const_cast<int*>(myarray-6600);
    printf("what_here: %d\n",*what_here);

    return 0;
}
4

2 回答 2

2

严格来说,对于两个连续的堆分配返回的指针之间的关系,没有什么明确的说法。分配器从两个完全不同的内存区域返回指针并非不可想象(例如,它可以根据请求的字节数使用不同的子堆)。

您的情况可能发生的是:

  1. 您的分配器以大于一个字节的块管理内存;
  2. 分配器使用与分配的内存相邻的几个字节作为其内部数据结构。

这两者都会产生开销。

此外,内存分配必须满足某些对齐要求。这通常会导致更多的开销。

于 2012-11-20T21:46:41.450 回答
1

aptr 和 amemTab 是 2 个单独分配的结果(一个通过 new,另一个通过 new[])

由于您的示例很小,因此堆非常空,并且它们的分配非常接近彼此,在您的情况下,相隔 64 个字节。然而,没有什么能阻止分配距离几兆。这完全取决于 Microsoft 对 HeapAlloc 的实现,所有 new、new[] 和 malloc 最终都会在其中执行。

如果您查看调试器中 2 分配之间的内容,您很可能会看到 0xAB 重复。这表明堆上的“无人区”。在较高的地址中,您更有可能看到 0xCD 指示尚未使用堆内存。

在一个完全不相关的注释中,您将 new 和 new[] 运算符视为您的示例中的 C 风格 malloc() 。我希望您知道有一些类型安全且更具可读性的分配方式。例如:

A *amemTab = new A[10]; // Allocated an array of 10 A's.
于 2012-11-20T21:51:50.053 回答