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())似乎也这样做!

编辑:仍然迷惑。在检查可被 64 整除的检查的构造函数中C进行检查后,如果不是,则出现异常,我得到了异常。最初我虽然它可能与堆栈上的实例有关,但是在将它们更改为基于堆之后,对齐检查仍然失败。我将回到一个调用并就地执行的工厂函数(这可能是最终会做的)thisthrowCposix_memalignnewstd::aligned_storage

4

3 回答 3

3

是的你可以; 使用std::is_polymorphic.

但是,如果您要对齐某些东西,请使用std::aligned_storagewith 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

停止尝试手动添加填充字节。只需定义要与对齐属性对齐的变量,如下所示:

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对齐,但它正在使您关心的变量不对齐:假设您实际上需要iValue在 64 字节边界上对齐,它不再在这样的边界上对齐。


iValue或....答案更简单:

停止添加您自己的填充字节!只需这样做:

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 字节边界上对齐,但它们都与邻居的iValue.

于 2013-02-01T21:37:42.403 回答