2

クラスに vtable があるかどうかをコンパイル時に検出する方法はありますか? クラスが 64 バイト境界に整列され、長さが 64 バイトであることを確認しようとしています。vtable を追加すると、クラス サイズが 128 バイトに増加します。

class __attribute__((aligned(64))) C
{
private:
    int64_t iValue;
    char iPadding[64 - sizeof(int64_t)];
};

これで問題ありません。でも

class __attribute__((aligned(64))) C
{
public:
    virtual ~C() {}

private:
    int64_t iValue;
    char iPadding[64 - sizeof(int64_t)];
};

物事を台無しにします。

回答:aligned位置を制御するだけでなく、パッドも使用します。__declspec(align())同じことをするようです!

編集:まだだまされています。Cそのチェックのコンストラクターにthis64 で割り切れるチェックを入れ、throwそうでない場合は例外を入れた後、例外が発生します。最初は、スタック上に のインスタンスを持っていることに関係しているかもしれませんが、Cそれらをヒープベースに変更した後も、アライメント チェックは失敗します。posix_memalignインプレースで呼び出して実行するファクトリ関数にフォールバックしますnew(これはおそらくstd::aligned_storage最終的に行うことです) 。

4

3 に答える 3

3

はい、できます。使用してstd::is_polymorphicください。

ただし、何かを整列させようとしている場合はstd::aligned_storage、placement を使用しますnew

std::aligned_storage<sizeof(C), 64> as;
C* c = new (&as) C;

// use c...

c->~C(); // call destructor ourselves
于 2013-02-01T20:58:58.233 に答える
3

パディング バイトを手動で追加する代わりに__attribute__((aligned(64)))、vtable が存在するかどうかにかかわらず、使用してコンパイラに整列させてみませんか? そうすれば、他の作業を必要とせずに常に 64 バイトのアライメントが得られ、vtable のサイズを知ることへの依存がなくなります。

于 2013-02-01T21:03:55.133 に答える
2

パディングバイトを手動で追加しようとするのをやめます。次のように、aligned属性に整列させる変数を定義するだけです。

class C
{
public:
    virtual ~C() {}

//private:
    __attribute__((aligned(64))) int64_t iValue;
};

void printAddr(C* a, int i)
{
    printf("&a[%d] = %p   &a[%d].iValue = %p\n", i, &a[i], i, &a[i].iValue);
}

int main()
{
    C a[8];
    printf("\nsizof(C) is: %d\n\n", sizeof(C));
    for (int i=0; i<sizeof(a)/sizeof(a[0]); ++i)
        printAddr(a, i);

    printf("\n");
}

クラスにvtableがある場合は、もちろんクラスのサイズが大きくなりますが、コンパイラーは必要なパディングを挿入し、必要に応じて包含クラスの配置要件を調整して、メンバーが最も厳密な(最大)配置は適切に配置されます。ところで、vtableはオブジェクトに格納されず、vtableポインタのみに格納されます。したがって、32ビットシステムを使用している場合、vtableポインターは4バイトしか使用しません。あなたが見た残りのsizeof(C)= 128は、型のオブジェクトの配列Cが整列されることを保証するためにコンパイラーが追加したパディングでしたが、それはあなたが気にする変数を整列から外してシフトしていました:あなたが実際に64バイトの境界に整列する必要がありますがiValue、そのような境界には整列されなくなりました。


または....実際にiValue64バイト境界に整列する必要はなく、クラスを64バイト境界に整列させる必要があるが、クラスに不必要にバルクを追加したくない場合は、答えはもっと簡単です:

自分のパディングバイトを追加するのはやめましょう!これを行うだけです:

class __attribute__((aligned(64))) C
{
public:
    virtual ~C() {}

//private:
    int64_t iValue;
};

void printAddr(C* a, int i)
{
    printf("&a[%d] = %p   &a[%d].iValue = %p\n", i, &a[i], i, &a[i].iValue);
}

int main()
{
    C a[8];
    printf("\nsizof(C) is: %d\n\n", sizeof(C));
    for (int i=0; i<sizeof(a)/sizeof(a[0]); ++i)
        printAddr(a, i);

    printf("\n");
}

このようにすると、iValueメンバーは64バイト境界で整列されなくなりますが、すべてのメンバーはネイバーのから64バイト離れていることに注意してくださいiValue

于 2013-02-01T21:37:42.403 に答える