2

是否有技术/库允许具有类层次结构(具有函数)的灵活性,但一旦在运行时virtual确定对象类型,就允许函数调用的虚拟化?

举一个简单的例子,假设我有一个程序从某个配置文件中读取形状类型(圆形、矩形、三角形等),以构建所述形状的某种数据结构(例如,vector<shape*>):

class shape {
public:
    virtual void draw() const = 0;
    // ...
};

class circle : public shape {
public:
    void draw() const;
    // ...
};

// ...
vector<shape*> shapes;

显然,如果我想绘制所有的形状,我可以这样做:

for ( auto&& s : shapes )
    s->draw();

每次完成这样的迭代时,都会调用shapes一个virtual函数来调用draw()每个形状。

但是假设一旦shapes创建,在程序的整个生命周期内都不会再改变;并进一步假设这draw()将被多次调用。如果知道实际形状后,有一种方法可以draw() 在运行时“去虚拟化”对 的调用,那就太好了。

我知道在编译时virtual去虚拟化函数调用的优化技术,但我不是在问这个。

如果有一个聪明的技巧可以直接在 C++ 中执行此操作,我会感到非常惊讶,因为这样做的一种方法是在运行时修改内存中的机器代码。但是那里有一些 C++ 库可以实现这样的事情吗?

我想这样的事情可能通过 LLVM 成为可能,因为它允许在运行时生成机器代码。有人为此使用过 LLVM 吗?也许是一个分层在 LLVM 之上的框架?

注意:解决方案必须是跨平台的,即至少使用 gcc/clangVC++。

4

1 回答 1

2

我相当肯定没有魔法之类的东西,“这里的编译器,没有我要定义的更多子类,这个列表也不会改变,所以消除虚函数调用开销”之类的东西。

在性能极其关键的情况下,您可以做的一件事是对形状列表进行排序,这有助于在性能极其关键的情况下进行虚拟调用。例如,不是像圆形、矩形、三角形、矩形、三角形、正方形等子类型的零星模式,而是要重新排列这些类型以形成如下形式:圆形、圆形、圆形、圆形、...、方形、 square, square, ...等。这有效地优化了分支预测。我不知道这种方法是否仍然适用,或者在最新的架构和优化器中产生很大的影响,但至少在不久前我还活着的时候,它非常有用。

关于 JIT,我一直在探索这个领域。我不一定建议尝试找到一种 JIT 解决方案来神奇地使您的 C++ 代码更快。

相反,我一直在探索它,因为我的软件已经有一种特定领域的语言,一种可视化的节点 GUI 编程语言,您可以在其中绘制节点(函数)之间的连接,而不是编写代码来制作新的东西,如着色器和图像过滤器(类似于虚幻引擎 4 的蓝图)。目前它的速度远不及手写本机代码,这就是我对探索代码生成/JIT 路线感兴趣的原因。它目前更像是一个解释器。

我已经为这些尝试了 Tiny C 和 LCC,但我发现它们相当令人失望的一件事是它们的优化器不如您的商业生产编译器那么复杂。我经常得到的结果平均比 MSVC 或 GCC 慢 3 到 4 倍。它们非常棒,因为它们非常轻巧且易于嵌入。

LLVM 似乎是一场绝妙的比赛,只是它非常庞大。在我们的核心级别区域中,我们有这种老派美学,其中旨在最大限度地重用的代码应该尽可能少地重用(以避免对外部包的零星依赖)。我很难将其降低到足以通过这些标准的轻量级,但我仍在研究它。

于 2015-05-19T09:49:06.150 回答