Inheritance 内联私有和受保护的虚拟函数调用 考虑下面的C++代码: class IFoo { public: virtual void Bar() const = 0; }; template <typename Derived> class AbstractFoo : public IFoo { public: void Bar() const override { int i = 0; auto derived = static_cast<const Derived *>(this); while (derived->ShouldBar(i++)) { derived->DoBar(); } } }; class FooImpl : public AbstractFoo<FooImpl> { private: bool ShouldBar(int i) const { return i < 10; } void DoBar() const { std::cout << "Bar!" << std::endl; } friend class AbstractFoo<FooImpl>; }; int main() { std::unique_ptr<IFoo> foo(new FooImpl()); foo->Bar(); }

Inheritance 内联私有和受保护的虚拟函数调用 考虑下面的C++代码: class IFoo { public: virtual void Bar() const = 0; }; template <typename Derived> class AbstractFoo : public IFoo { public: void Bar() const override { int i = 0; auto derived = static_cast<const Derived *>(this); while (derived->ShouldBar(i++)) { derived->DoBar(); } } }; class FooImpl : public AbstractFoo<FooImpl> { private: bool ShouldBar(int i) const { return i < 10; } void DoBar() const { std::cout << "Bar!" << std::endl; } friend class AbstractFoo<FooImpl>; }; int main() { std::unique_ptr<IFoo> foo(new FooImpl()); foo->Bar(); },inheritance,compiler-optimization,jit,virtual-functions,crtp,Inheritance,Compiler Optimization,Jit,Virtual Functions,Crtp,正如您所看到的,仍然存在一些尴尬,因为分部方法必须返回void,并且抽象类的代码需要复制 是否有任何语言/运行时环境可以对简单的虚拟受保护方法执行此优化 我认为问题可以归结为这样一个事实:虚拟公共方法不应该为每个实现生成机器代码,而是为每个具体的类生成机器代码。考虑一个简单的vtable,FooImpl的vtable中的槽不应该在IFoo#Bar的槽中容纳AbstractFoo#Bar,而是一个专门的edFooImpl#Bar,对JIT生成的ShouldBar和DoBar进行非虚拟/内联调用 是

正如您所看到的,仍然存在一些尴尬,因为分部方法必须返回
void
,并且抽象类的代码需要复制

是否有任何语言/运行时环境可以对简单的虚拟受保护方法执行此优化

我认为问题可以归结为这样一个事实:虚拟公共方法不应该为每个实现生成机器代码,而是为每个具体的类生成机器代码。考虑一个简单的vtable,
FooImpl
的vtable中的槽不应该在
IFoo#Bar
的槽中容纳
AbstractFoo#Bar
,而是一个专门的ed
FooImpl#Bar
,对JIT生成的
ShouldBar
DoBar
进行非虚拟/内联调用


是否有任何环境能够执行此优化,或者至少在这方面进行一些研究?

不要使用JIT,使用CPU的分支预测器。任何合适的CPU都会尝试缓存每个间接分支指令的目标,因此正确预测的间接分支的成本与条件分支的成本相同ch,通常为零

优化此模式与通常的优化过程没有什么不同。探查器应将特定的间接分支指令标记为瓶颈。通过将每条慢指令划分为多条更好的可预测指令进行优化,例如

if ( likely_to_be_FooImpl ) {
    foo->Bar();
} else {
    foo->Bar();
}
阻止编译器删除明显多余的分支只是一个练习;)。或者,理想情况下,一个分支根本不需要间接分派:

if ( certain_to_be_FooImpl ) {
    static_cast< FooImpl * >( foo )->fooImpl::Bar();
} else {
    foo->Bar();
}
if(某些要成为){
静态_cast(foo)->FooImpl::Bar();
}否则{
foo->Bar();
}

在任何情况下,JIT都需要寻找本地程序状态和分支目标之间的相关性。JIT可能会注意到分支倾向于去某个特定的目的地,但CPU已经在硬件中对这种情况进行了优化。相反,只要分支数不超过预测器的内存限制当你在C++中有你所需要的一切时,为什么要寻找其他语言?而C++对(几乎)零成本抽象来说是很好的,比如CRTP不能被称为直觉。此外,有一些垃圾收集器的优点是不容易用RAII来模拟的。(例如,摊销小对象的分配和解除分配成本)并需要一个托管运行时。尽管存在一些问题,但我还是最好使用C++/CLI…:)
if ( certain_to_be_FooImpl ) {
    static_cast< FooImpl * >( foo )->fooImpl::Bar();
} else {
    foo->Bar();
}