有没有办法在编译时检测一个类是否有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
最终做的事情)
答案 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字节。