vtable的编译时检测

时间:2013-02-01 20:58:14

标签: c++

有没有办法在编译时检测一个类是否有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的构造函数中检查this是否可被64整除后,throw如果不是,则会出现例外情况。最初我虽然它可能与堆栈上有C的实例有关,但在将它们更改为基于堆之后,对齐检查仍然失败。我将回到调用posix_memalign并执行就地new的工厂函数(这可能是std::aligned_storage最终做的事情)

3 个答案:

答案 0 :(得分:3)

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

如果您尝试对齐某些内容,请将std::aligned_storage与展示位置new一起使用:

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

// use c...

c->~C(); // call destructor ourselves

答案 1 :(得分:3)

不是手动添加填充字节,为什么不使用__attribute__((aligned(64)))并让编译器为你调整它是否存在vtable?然后你将总是得到64字节对齐而不需要其他工作,并且它消除了对知道vtable大小的依赖。

答案 2 :(得分: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的对象数组对齐,但它正在移动您关心的变量alignment:假设你实际上需要在64字节边界上对齐iValue,它就不再在这样的边界上对齐。


OR ....如果你实际上不必让iValue本身在64字节边界上对齐,你只需要在64字节边界上对齐你的类但你不想要为了不必要地增加课程的批量,答案更简单:

停止添加自己的PADDING BYTES!就这样做:

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都是64字节。