vtable 的编译时检测
Compile-time detection of vtable
有没有办法在编译时检测一个类是否有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
最终所做的)
与其手动添加填充字节,为什么不直接使用__attribute__((aligned(64)))
并让编译器为您对齐它,无论是否存在 vtable?然后,您将始终获得 64 字节对齐,无需其他工作,并且它消除了对了解 vtable 大小的依赖。
是的,你可以;使用 std::is_polymorphic
.
如果您尝试对齐某些内容,请使用带有放置new
的std::aligned_storage
:
std::aligned_storage<sizeof(C), 64> as;
C* c = new (&as) C;
// use c...
c->~C(); // call destructor ourselves
停止尝试手动添加填充字节。 只需定义要与对齐属性对齐的变量,如下所示:
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 = %pn", i, &a[i], i, &a[i].iValue);
}
int main()
{
C a[8];
printf("nsizof(C) is: %dnn", 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
, 它不再在这样的边界上对齐。
或。。。。 如果您实际上不必在 64 字节边界上对齐iValue
本身,并且只需要在 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 = %pn", i, &a[i], i, &a[i].iValue);
}
int main()
{
C a[8];
printf("nsizof(C) is: %dnn", sizeof(C));
for (int i=0; i<sizeof(a)/sizeof(a[0]); ++i)
printAddr(a, i);
printf("n");
}
请注意,如果这样做,iValue
成员不再在 64 字节边界上对齐,但它们都与相邻成员的iValue
相距 64 个字节。
- 编译的C可执行文件被Windows defender检测为病毒
- CodeLite 不会检测(安装)MinGW - 即使使用手动配置也不会编译
- 检测编译时文本和常量
- 如何在编译时检测C 17中是否没有虚拟基础
- 有没有办法在编译时检测是否可以使用一组给定的参数类型成功调用通用 lambda?
- 编译时未检测到主要功能
- 参数类型的编译时类型检测
- 使用SFINAE检测编译时间是否存在过载的独立式功能
- 如何在编译时检测 C++ 代码中的 SQL 错误
- 如何在编译时检测ABI
- 我可以检测编译时使用的标记调度重载吗?
- 如何检测编译时是否shared_ptr类型
- 检测或避免在编译时间上暂时提及暂时的提及
- 在编译时检测std :: size_t类型以调用正确的功能
- 编译共享对象时出错:未检测到C++类定义
- 在编译时检测是否存在默认构造函数
- 编译弃用电话的时间检测
- 是否可以在编译时间作为宏上检测GCC编译标志
- 检测编译时是否存在长长
- 在大型C++项目中,我应该如何检测编译时间的瓶颈