[英]Is There Any Way To Copy vtable From Host To Device (CUDA & C++)
[英]Is there a way to prevent the vtable from being emitted in c++?
我正在制作一个库,它要求类必须继承其他类才能执行特定操作。 然而,这不是简单的多态性。 这些类是虚函数的代码生成器,没有数据并且依赖于CRTP,因此它们本身不需要vtable。
有没有办法阻止为这些类发出 vtable? 我假设虚函数指针将传递给派生类,而虚析构函数将跳过这些类。 有点像将这些类融合在一起。
如果在 C++ 域中没有任何通用内容,那么可能特定于 clang、gcc 和 vc?
#include<iostream>
template <typename D, typename B>
struct jelly : B
{
virtual void do_stuff() { static_cast<D*>(this)->D::do_some_other_stuff(); }
};
template <typename D>
struct jelly<D, void>
{
virtual void do_stuff() { static_cast<D*>(this)->D::do_some_other_stuff(); }
};
struct A : jelly<A, void>
{
void do_some_other_stuff() { std::cout << "A::do_some_other_stuff()\n"; }
};
struct B : jelly<B, A>
{
void do_some_other_stuff() { std::cout << "B::do_some_other_stuff()\n"; }
};
int main()
{
A a;
a.do_stuff(); // output: A::do_some_other_stuff()
B b;
b.do_stuff(); // output: B::do_some_other_stuff()
A& aa = b;
aa.do_stuff(); // output: B::do_some_other_stuff()
}
只是为了澄清,这只是一个例子。 它确实运行了,但jelly
代表的类别数量实际上是 3 个不同的类别。 一个是由开发人员使用jelly
库显式继承的,另外两个是隐式完成的,然后再继承回开发人员自己的类。 正是因为班级的数量会增加 3 倍,这才让我感到担忧,这也是我问这个问题的原因。
如果您将成员函数声明为virtual
,则该类必须具有实现认为必要的任何机制来完成 C++ 要求virtual
函数执行的操作。 但这也意味着该类型现在是多态的,这要求该类型能够做 C++ 要求的多态类型可以做的事情。 具体来说, typeid
和dynamic_cast
。
这很重要。 从多态类型派生的类本身就是多态的,无论它是否覆盖任何virtual
函数。 这意味着您必须能够从该类的实例中获取类型信息。 你是否真的这样做无关紧要; 你可以,因此必须存在机器来允许它。
对于 vtable 实现,这通常意味着每个多态类型都需要有一个唯一的vtable 对象。 除了指向虚函数的指针之外,vtable 还会有一个索引或指向某些类型特定信息的指针。 由于 vtable 往往非常小,因此拥有另一个 vtable 并不是特别繁重。 实际上,类型标识信息本身通常比 vtable 更重要。
现在,编译器具有允许您删除运行时类型识别的所有痕迹的选项。 具体来说, typeid
不再起作用,并且dynamic_cast
永远不会抛出,因此不需要验证强制转换,编译器不再需要为A
提供与jelly<A>
不同的 vtable。 但是, 该功能的主要目标是type_info
对象和其他标识信息的表。 所以我不能谈论这个特性对 vtable 生成的影响。
然而,最终,你无能为力。 这些类可能会得到 vtables,就是这样。
我唯一知道的编译器扩展是 MSVC 的__declspec(novtable)
:
这种形式的
__declspec
可以应用于任何类声明,但只能应用于纯接口类,即永远不会自己实例化的类。__declspec
阻止编译器生成代码来初始化类的构造函数和析构函数中的 vfptr。 在许多情况下,这会删除与该类关联的对 vtable 的唯一引用,因此链接器将删除它。 使用这种形式的__declspec
可以显着减少代码大小。如果您尝试实例化标有
novtable
的类,然后访问类成员,您将收到访问冲突 (AV)。
当您使用 MSVC 的__interface
关键字时,该修饰符是隐含的。
你做:
template <typename D, typename B>
struct jelly : B
{
virtual void do_stuff() { D::do_some_other_stuff(); }
};
然后你做:
struct B : jelly<B, A>
{
void do_some_other_stuff() { std::cout << "B::do_some_other_stuff()\n"; }
};
这意味着struct B
取决于jelly<B, A>
。 那,反过来需要调用B
(又名D
)函数do_some_other_stuff
,但B
尚未定义。 也许您需要将void do_stuff
移到类声明之外。 无论如何,当您将其声明为virtual
,它不应该被内联。
另外,您正在使用
struct A : jelly<A, void>
翻译成:
struct jelly : void
{
virtual void do_stuff() { A::do_some_other_stuff(); }
};
你希望如何从void
继承?
样式说明:不要使用struct
只是为了避免public
。 当应该有一个class
(因为你正在继承)而不是任何typename
时,不要使用typename D
。 不要使用名称 A、B、C、D,输入一些更具描述性的名称。 struct jelly : B
是从typename B
还是从struct B
继承?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.