Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/148.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;:类专门化是一致性编译器的有效转换吗?_C++_Compiler Construction_Compiler Optimization_Virtual Functions_Vtable - Fatal编程技术网

C++ C++;:类专门化是一致性编译器的有效转换吗?

C++ C++;:类专门化是一致性编译器的有效转换吗?,c++,compiler-construction,compiler-optimization,virtual-functions,vtable,C++,Compiler Construction,Compiler Optimization,Virtual Functions,Vtable,希望这对于StackOverflow来说不是一个太专业化的问题:如果是并且可以迁移到其他地方,请让我知道 许多年前,我写了一篇本科论文,提出C++和相关语言的各种去虚拟化技术,通常基于代码路径的预编译专门化(有点像模板)的想法。但是,如果在编译时无法选择专门化,则在运行时通过检查选择正确的专门化(模板必须如此) (非常)基本的想法如下……假设您有一个类C,如下所示: class C : public SomeInterface { public: C(Foo * f) : _f(f) {

希望这对于StackOverflow来说不是一个太专业化的问题:如果是并且可以迁移到其他地方,请让我知道

许多年前,我写了一篇本科论文,提出C++和相关语言的各种去虚拟化技术,通常基于代码路径的预编译专门化(有点像模板)的想法。但是,如果在编译时无法选择专门化,则在运行时通过检查选择正确的专门化(模板必须如此)

(非常)基本的想法如下……假设您有一个类
C
,如下所示:

class C : public SomeInterface
{
public:
    C(Foo * f) : _f(f) { }

    virtual void quack()
    {
        _f->bark();
    }

    virtual void moo()
    {
        quack(); // a virtual call on this because quack() might be overloaded
    }

    // lots more virtual functions that call virtual functions on *_f or this

private:
    Foo * const _f; // technically doesn't have to be const explicitly
                    // as long as it can be proven not be modified
};
C::C(Foo * f) : _f(f)
{
    if(f->vptr == vtable_of_FooA) // obviously not Standard C++
        this->vptr = vtable_of_C_FooA; 
    else if(f->vptr == vtable_of_FooB)
        this->vptr = vtable_of_C_FooB;
    // otherwise leave vptr unchanged for all other values of f->vptr
}
您知道存在
Foo
的具体子类,如
FooA
FooB
等,具有已知的完整类型(不一定有详尽的列表),然后您可以为
Foo
的某些选定子类预编译
C
的专门版本,例如(注意,这里没有特意包括构造函数,因为它不会被调用):

并将
C
的构造函数替换为以下内容:

class C : public SomeInterface
{
public:
    C(Foo * f) : _f(f) { }

    virtual void quack()
    {
        _f->bark();
    }

    virtual void moo()
    {
        quack(); // a virtual call on this because quack() might be overloaded
    }

    // lots more virtual functions that call virtual functions on *_f or this

private:
    Foo * const _f; // technically doesn't have to be const explicitly
                    // as long as it can be proven not be modified
};
C::C(Foo * f) : _f(f)
{
    if(f->vptr == vtable_of_FooA) // obviously not Standard C++
        this->vptr = vtable_of_C_FooA; 
    else if(f->vptr == vtable_of_FooB)
        this->vptr = vtable_of_C_FooB;
    // otherwise leave vptr unchanged for all other values of f->vptr
}
因此,基本上,正在构造的对象的动态类型是根据其构造函数的参数的动态类型来更改的。(注意,您不能使用模板来执行此操作,因为只有在编译时知道
f
的类型,您才能创建
C
)。从现在开始,对
FooA::bark()的任何调用
C::quack()
只涉及一个虚拟调用:对
C::quack()
的调用静态绑定到动态调用
FooA::bark()
的非专用版本,或者对
C::quack()
的调用动态转发到
C\u FooA::quack()
静态调用
FooA::bark()
。此外,如果流分析器有足够的信息对
C\u FooA::quack()
进行静态调用,则在某些情况下,动态调度可能会被完全消除,如果允许内联,这在紧密循环中可能非常有用。(虽然从技术上讲,即使没有这种优化,您也可能没问题……)

(请注意,此转换是安全的,尽管不太有用,即使
\u f
是非常量且受保护的,而不是私有的,
C
是从不同的翻译单元继承的……为继承的类创建vtable的翻译单元根本不知道inhe的专门化和构造函数。)rited类只需将
this->vptr
设置为自己的vtable,而vtable不会引用任何专用函数,因为它对这些函数一无所知。)

为了消除一个级别的间接寻址,这似乎需要付出很多努力,但关键是,您可以对任意嵌套级别执行此操作(遵循此模式的任何虚拟调用深度都可以减少到一个)仅基于翻译单元内的本地信息,并以一种灵活的方式进行,即使在您不知道的其他翻译单元中定义了新类型……您可能会添加大量代码膨胀,如果您天真地这样做,您将不会有这些代码膨胀

无论如何,独立于这种优化是否真的有足够的BUG,值得付出努力,并且值得在可执行的<强>中的空间开销,我的问题是,标准C++中有什么东西会阻止编译器执行这样的转换吗? 我的感觉是否定的,因为该标准根本没有规定如何进行虚拟分派或如何表示成员函数的指针。我很确定RTTI机制没有阻止

C
C\u FooA
为所有目的伪装成同一类型,即使它们有不同的虚拟表。我唯一能想到的另一件事可能是仔细阅读ODR,但可能不是

我忽略了什么东西?除了ABI/Link问题,这样的转换是可能的而不破坏一致的C++程序吗?(此外,如果是,这可以用Itand和/或MSVC AbIS来完成吗?我很肯定答案是肯定的,但是希望有人能确认。)


<> > >编辑< <强>:有人知道在C++、java、C语言的任何主流编译器/JIT中是否都有类似的东西(见下面的评论中的讨论和链接聊天)?我知道JIT在调用站点上直接进行虚拟静态绑定/内联,但我不知道他们是否做了类似的事情。(基于在构造函数上而不是在每个调用站点上进行的单一类型检查生成和选择了全新的vtables)。

乍一看,这听起来像是一个以c++为中心的版本。我认为V8和Oracle的JVM都使用它,我知道这一点

回答你原来的问题:我认为标准中没有任何东西禁止这种实现。C++采用“AS”。非常严肃地对待规则;只要忠实地实现正确的语义,就可以用任何你喜欢的疯狂方式来实现。C++虚拟调用不是很复杂,所以我怀疑你会在任何边缘情况下跳过(与如果你试图用静态绑定做一些聪明的事情不同)。

标准C++中有什么东西可以阻止编译器执行这样的转换?

如果你确定可观察到的行为是不变的,那就不是了——这是标准的第1.9节“假设规则”

但这可能会使证明您的转换是正确的变得相当困难:12.7/4:

当从构造函数(包括非静态数据成员的mem初始值设定项或大括号或相等初始值设定项)或从