Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/149.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++ le指针,从虚拟表中的适当偏移量获取函数指针,并通过该指针调用函数_C++_Optimization_Inheritance_Virtual - Fatal编程技术网

C++ le指针,从虚拟表中的适当偏移量获取函数指针,并通过该指针调用函数

C++ le指针,从虚拟表中的适当偏移量获取函数指针,并通过该指针调用函数,c++,optimization,inheritance,virtual,C++,Optimization,Inheritance,Virtual,这比静态调用稍微贵一些,但对于“正常”使用来说仍然被认为是非常便宜的。如果需要压缩每一个性能,考虑在编译时指定所有类型以允许使用非虚函数。 编译器是否能够对其进行优化,并理解如果我使用PriciseMath初始化MyMath,我只想调用正常的Sin和Cos函数 如果编译器能够(向自己)证明一个对象在运行时将具有特定类型,那么它将能够发出一个静态函数调用,即使函数本身被声明为虚函数 然而,编译器并不能保证足够聪明,能够真正做到这一点。保证静态调用的唯一方法是使用非虚拟函数 我可以改变我的设计来帮助

这比静态调用稍微贵一些,但对于“正常”使用来说仍然被认为是非常便宜的。如果需要压缩每一个性能,考虑在编译时指定所有类型以允许使用非虚函数。

编译器是否能够对其进行优化,并理解如果我使用PriciseMath初始化MyMath,我只想调用正常的Sin和Cos函数

如果编译器能够(向自己)证明一个对象在运行时将具有特定类型,那么它将能够发出一个静态函数调用,即使函数本身被声明为虚函数

然而,编译器并不能保证足够聪明,能够真正做到这一点。保证静态调用的唯一方法是使用非虚拟函数

我可以改变我的设计来帮助编译器理解和优化我的代码吗

  • 消除虚拟调用开销:如果不需要在运行时更改实现,则在编译时指定类型并完全停止使用虚拟函数。模板在以通用方式执行此操作时是不可或缺的
  • 消除静态函数调用开销:在头中提供函数体,允许编译器内联函数调用
(这是这两种技术的一个很好的例子。)


最后,如果绩效对你来说真的很重要,不要仅仅依赖于其他人(包括我)的建议-总是自己进行测量

如果调用一个调用“Math.sin”的虚拟函数而不是直接调用它,我会付出多少时间代价

虚拟调用是通过取消引用虚拟表指针、从虚拟表中的适当偏移量获取函数指针并通过该指针调用函数来实现的

这比静态调用稍微贵一些,但对于“正常”使用来说仍然被认为是非常便宜的。如果需要压缩每一个性能,考虑在编译时指定所有类型以允许使用非虚函数。

编译器是否能够对其进行优化,并理解如果我使用PriciseMath初始化MyMath,我只想调用正常的Sin和Cos函数

如果编译器能够(向自己)证明一个对象在运行时将具有特定类型,那么它将能够发出一个静态函数调用,即使函数本身被声明为虚函数

然而,编译器并不能保证足够聪明,能够真正做到这一点。保证静态调用的唯一方法是使用非虚拟函数

我可以改变我的设计来帮助编译器理解和优化我的代码吗

  • 消除虚拟调用开销:如果不需要在运行时更改实现,则在编译时指定类型并完全停止使用虚拟函数。模板在以通用方式执行此操作时是不可或缺的
  • 消除静态函数调用开销:在头中提供函数体,允许编译器内联函数调用
(这是这两种技术的一个很好的例子。)



最后,如果绩效对你来说真的很重要,不要仅仅依赖于其他人(包括我)的建议-总是自己进行测量

如果您可以提供不同的二进制文件,只需执行以下操作:


然后使用
-DFAST_MATH
调用编译器,生成快速二进制文件,而不生成精确的二进制文件。

如果可以提供不同的二进制文件,只需执行以下操作:


然后用
-DFAST_MATH
调用编译器,生成快速二进制文件,而不生成精确的二进制文件。

Re 2:有时,它可以知道(请参阅设备化,例如
Foo*x=new Bar();…x->virtualFunc()
其中
不重新分配
x
)。但是,是的,不太频繁,也不在最有趣的用例中。@delnan啊,我不知道设备化。我会更新我的答案,非常感谢。Re 2:有时,它可以知道(请参阅设备化,例如,
Foo*x=new Bar();…x->virtualFunc()
其中,
不会重新分配
x
)。但是,是的,不太频繁,也不在最有趣的用例中。@delnan啊,我不知道设备化。我会更新我的答案,非常感谢。也许继承不是适合你的情况的成语。在你解决这个问题之前,先试试其他的C++技术。需要客户能够改变精度,或者你能提供两个不同的二进制文件吗?假设我可以提供不同的二进制信息,也许继承不是你的习惯。在你解决这个问题之前,先试试其他标准C++技术。需要客户端能够改变精度,或者你能提供两个不同的二进制文件吗?假设我可以提供不同的二进制文件,你不应该内嵌“DO”吗?还有?根本没有理由写内联,因为所有函数都是隐式内联的。@OopsUser它并不像听起来那么重要,do函数只会被调用几次,但是如果你愿意,你可以一直内联它。@ipc这是真的,我编写它们通常有两个原因,即使大多数好的编译器完全忽略内联语句。第一个是让其他程序员知道它被放在类声明中的原因,第二个是因为有时我无法使用好的编译器。我不想制作我的整个函数模板,如果t是一个模板,我如何编写math.cos?我可以传递而不是T“int”或其他什么,然后它就不会编译了。你不也内联“do”吗?根本没有理由内联写,因为所有函数都是隐式内联的。@OopsUser
interface MyMath
{
    double PreciseSin(double x);
    double PreciseCos(double x);
}
class PreciseMath{
    public:
    inline double sin(double sin){
        //code goes here
    }
    inline double cos(double sin){
        //code goes here
    }
    inline double sqrt(double sin){
        //code goes here
    }
};
class FastMath{
    public:
    inline double sin(double sin){
        //code goes here
    }
    inline double cos(double sin){
        //code goes here
    }
    inline double sqrt(double sin){
        //code goes here
    }
};
template<class T>
class ExpensiveOP{
    public:
    T math;
    void do(){
        double x = math.sin(9);
        x=math.cos(x);
        //etc
    }
}
ExpensiveOP<PreciseMath> preciseOp;
ExpensiveOP<FastMath> fasterOp;
  namespace MyMath {
#ifdef FAST_MATH
    double sin(double x) { /* do it fast */ }
    double sos(double x) { /* do it fast */ }
#else
    double sin(double x) { /* do it precise */ }
    double sos(double x) { /* do it precise */ }
#endif
  }