这种手动去虚拟化合法/可行吗?

Posted

技术标签:

【中文标题】这种手动去虚拟化合法/可行吗?【英文标题】:Is this manual devirtualization legal / viable? 【发布时间】:2019-11-06 09:32:16 【问题描述】:

对于我的一个项目,我终于需要使用我的第一个多态类(std::cout 除外)。

我正在研究如何确保至少在某些情况下我有 100% 的非虚拟化调用。

这段代码合法可行吗?

dynamic_cast 会有多慢?如果我在构造函数中支付一次,那么我将始终可以直接使用 B 类,所以这听起来不错?

C 风格转换之后会很快还是我必须存储指向B 的指针?

struct A
    virtual void x();
;

struct B : A
    void x() override;
;

struct X
    A *a;
    bool fB;

    X(A &a) : a(&a), fB( dynamic_cast<B *>(&a) )

    void f()
        if (fB)
            ((B*)a)->x();
        else
            a->x();
        
    
;


void fn(A &a)
    X x(a);

    x.f();



int main()
    B b;

    X x(b);

    x.f();

【问题讨论】:

多态性的好处是虚函数将被解析并自动调用正确的类。所以你不需要fB 或动态演员表。只需 void f() a-&gt;x(); 应该可以正常工作。 作为一般提示:所有 C 风格的转换都应该被视为你做错了什么的危险信号。 看来你没有抓住重点。循环调用非去虚拟化的虚函数,每次都会解析虚函数。 因为我想要性能,但我不想改变X的类型,否则我会使用模板 那么自然而然的后续问题是,您是否已将其视为程序中的前一两个瓶颈?所有手动和手工优化(包括编译时多态性或其他绕过虚拟分派的尝试)都会导致代码晦涩难懂,需要大量文档来解释所做的事情以及原因。它也往往会导致模糊的错误,需要大量的额外测试。如果做得不好,根本不会导致“效率”发生任何(实际或感知的)变化。 【参考方案1】:

对于您现有的代码,我实际上希望您的编译器优化掉 if 语句和您的强制转换,因为这会影响代码。

从编译器的角度来看,您的代码库可能如下所示:

struct A
    virtual void x();
;

struct B : A
    void x() override;
;

struct C : B
    void x() override;
;

因此,当 is 看到您的演员表和函数调用时:static_cast&lt;B*&gt;(a)-&gt;x() 它仍然必须访问与调用 a-&gt;x() 时相同的虚拟表,因为可能存在潜在的 C 类。 (请注意,我使用的是 static_cast,因为 c 风格的强制转换是错误的来源)

如果您想直接调用 B,最好将方法或类设为 final。另一个好方法是使用配置文件引导优化,在这种情况下,他们经常比较 vtable 指针。

回答你的附带问题?

代码合法吗?是的。 这可行吗?是的,鉴于上述说明。 dynamic_cast 的速度有多慢?慢,我会争辩为此写一个好的基准,但是,我不知道如何做到这一点并使其变得现实。 这是一种好的做法吗?不,它会降低多态性的可用性。 static_cast 会很快吗?是的,它很快,在这种特定情况下,不需要任何说明。与 bool 相比,存储指向 B 的指针在复杂继承的特定情况下都可以得到改善。如果它需要额外的内存,它也可能导致性能下降。只需在您的可执行文件中添加额外的程序集,就可以实现另一个减少。

我的建议,尤其是因为您是 C++ 新手:不要这样做或任何其他手动优化。编译器可以为您做很多事情。每次手动优化都会导致之后的额外维护,只有在您确实遇到性能问题时才使用这些技巧。

哦,如果你想知道它的实际汇编代码是什么,你可以在compiler explorer进行实验

【讨论】:

【参考方案2】:

您尝试将虚拟调用更改为分支。

我已经不确定它是否更快,

但更糟糕的是,您不会删除虚拟调用,因为 B 可以有子子级,您至少必须使 void B::x() final 允许编译器对调用进行虚拟化。

如果编译器可以像main 那样访问具体类型(和代码),它可能能够单独对调用进行去虚拟化。

【讨论】:

以上是关于这种手动去虚拟化合法/可行吗?的主要内容,如果未能解决你的问题,请参考以下文章

手动安装openstack并配置虚拟化集成VM

虚拟化vmware esxi 安装在u盘上,却无法识别本地磁盘,是否只能安装在本地磁盘中

中本聪币core合法吗

vbox虚拟机使用vdi和vhd磁盘,性能有差别吗?

AZURE技能分享 | 通过Azure Automation自动化脚本 定时开启和关闭虚拟机

这种使用虚拟保护方法扩展库的方法安全吗?