2013-02-01 66 views
2

有没有办法在编译时检测一个类是否有vtable?我试图确保 一个类对齐到64个字节的边界,并且是64个字节的长度。添加一个vtable将类大小增加到128字节。编译时检测vtable

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

iPadding []的目的是什么?只是为了填补你的类,所以如果你有一个他们的数组,他们的iValue成员将始终在一个64字节的边界? – phonetagger

+0

使用C++ 11,您也可以使用['std :: aligned_storage'](http://en.cppreference.com/w/cpp/types/aligned_storage)来对齐您的类。 – ipc

+0

@James:alignment可以添加填充,因为这就是编译器可以确保数组元素对齐的方式。 –

回答

3

,而无需手动添加填充字节,为什么不使用__attribute__((aligned(64))),让编译器对准它为您是否有一个vtable礼物?然后你将总是得到64字节的对齐方式,而不需要其他的工作,并且它消除了知道vtable大小的依赖性。

+0

似乎他已经在做 – thang

+0

我不' t想在与iValue相同的缓存行上有任何其他变量ipadding从不使用vtable的存在可能会在作品中抛出扳手尚不确定 – James

+0

**长度为64字节**是问题所在? – thang

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 
+0

这就是为什么我喜欢C++ 11 :) – buc

+0

请注意,这可能会或可能不会对解决*实际问题*(对齐)有任何影响。 –

+0

这在编译时起作用?我可以问你一个例子吗?我尝试过''char *''[64 - (sizeof(int64_t)+ std :: is_polymorphic :: value?8:0];'和gcc不喜欢它......“不完整类型'class C'” – James

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指针。所以如果你在32位系统上,vtable指针只占用4个字节。您看到的sizeof(C)= 128的其余部分是编译器添加的填充,以确保类型为C的对象数组将被对齐,但它正在将您关心的变量移动不对齐:假设您实际上需要在一个64字节边界上对齐的iValue,它不再在这样的边界上对齐。


OR ....如果你实际上并不拥有iValue本身一个64字节的边界上对齐,而你只需要你的类在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字节边界对齐,但他们是从他们的邻居的iValue所有64个字节的路程。