2

次のコードで、ポインターaptrとamemTabの違いが、割り当てられた配列のサイズ(10 * sizeof(A))ではなく64バイト(sizeof(A)が4)である理由を知りたいと思います。

デバッグモードの場合:

aptr 0x00395e38

amemTab 0x00395e78

Win XP Home Edition、MSVS2010、x86 Intel 1.86

パディングと関係があると思いますか?(私がテストしているものを正確に示したいので、基本クラスと派生クラスのコードを削除していませんが、ここでは冗長です。2行についてのみ話します。

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

厳密に言えば、2つの連続するヒープ割り当てによって返されるポインター間の関係については明確なことは何も言えません。アロケータが2つの完全に異なるメモリ領域からポインタを返すことは考えられません(たとえば、要求されたバイト数に応じて異なるサブヒープを使用できます)。

あなたの場合に起こりそうなことは次のとおりです。

  1. アロケータは、1バイトを超えるチャンクでメモリを管理します。
  2. アロケータは、割り当てられたメモリに隣接する数バイトを内部データ構造に使用します。

これらは両方ともオーバーヘッドが発生します。

また、メモリ割り当ては特定のアライメント要件を満たす必要があります。これは一般に、さらなるオーバーヘッドにつながる可能性があります。

于 2012-11-20T21:46:41.450 に答える
1

aptrとamemTabは、2つの別々の割り当ての結果です(1つはnewを通過し、もう1つは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 に答える