(gcc)编译器是否优化了空体函数?

时间:2014-02-20 16:36:41

标签: c++ gcc optimization

使用基于策略的设计,EncapsulatedAlgorithm

template< typename Policy>
class EncapsulatedAlgorithm : public Policy
{
    double x = 0; 

    public: 
        using Policy::subCalculate; 

        void calculate()
        {
            Policy::subCalculate(x); 
        }
    protected:
        ~EncapsulatedAlgorithm() = default;
};

可能有一个执行子计算的策略Policy。算法不需要子计算:在某些情况下可以使用它来加速算法收敛。因此,为了对此进行建模,假设有三种策略。

只是“记录”某事的人:

struct log
{
    static void subCalculate(double& x)
    {
        std::cout << "Doing the calculation" << endl; 
    }
};

计算:

struct calculate
{
    static void subCalculate(double& x)
    {
        x = x * x; 
    }
};

和一个把它们全部带到黑暗中并绑定它们:D - 它完全没有

struct doNothing
{
    static void subCalculate(double& x)
    {
        // Do nothing. 
    }
};

以下是示例程序:

typedef EncapsulatedAlgorithm<doNothing> nothingDone; 
typedef EncapsulatedAlgorithm<calculate> calculationDone; 
typedef EncapsulatedAlgorithm<loggedCalculation>  calculationLogged; 

int main(int argc, const char *argv[])
{
    nothingDone n; 
    n.calculate(); 

    calculationDone c; 
    c.calculate();

    calculationLogged l; 
    l.calculate(); 

    return 0;
}

here是实例。我尝试在启用优化的情况下检查gcc生成的汇编代码:

g++ -S -O3 -std=c++11 main.cpp

但是我对于大会没有足够的了解以确定地解释结果 - 结果文件很小并且我无法识别函数调用,因为所有策略的静态函数的代码都是内联的。

我能看到的是,当没有为主函数设置优化时,有一个call和一个与'doNothing :: subCalculate'相关的后续leave

call    _ZN9doNothing12subCalculateERd
leave

以下是我的问题:

  1. 为了能够阅读g++ -S喷出的内容,我从哪里开始学习?
  2. 是否将空函数优化掉了,main.s中哪些是哪些行?
  3. 这个设计是O.K.?通常,实现一个什么都不做的函数是坏事,因为界面说的是完全不同的东西(subCalculate而不是doNothing),但是在策略的情况下,策略名称明确指出功能不会做任何事情。否则我需要输入像enable_if等类型的特征,只是为了排除单个函数调用。

2 个答案:

答案 0 :(得分:5)

我去了http://assembly.ynh.io/,显示了汇编输出。我

template< typename Policy>
struct EncapsulatedAlgorithm : public Policy
{
        void calculate(double& x)
        {
            Policy::subCalculate(x); 
        }
};
struct doNothing
{
    static void subCalculate(double& x)
    {
    }
};
void func(double& x) {
   EncapsulatedAlgorithm<doNothing> a;
   a.calculate(x);
}

得到了这些结果:

            .Ltext0:
                .globl  _Z4funcRd 
            _Z4funcRd:
            .LFB2:
                .cfi_startproc    #void func(double& x) {
            .LVL0:
0000 F3             rep           #not sure what this is
0001 C3             ret           #}
                .cfi_endproc
            .LFE2:
            .Letext0:

好吧,我只在组装中看到两个操作码。 rep(不知道那是什么)和结束功能。似乎G ++编译器可以轻松地优化函数体。

答案 1 :(得分:3)

  

为了能够阅读g ++ -S喷出的内容,我从哪里开始学习?

此网站不适用于推荐阅读材料。谷歌“x86汇编语言”。

  

是否将空函数优化掉,而main.s中的那些是那些行?

启用优化器的时候,生成的.S中不会有任何行。你已经在未经优化的输出中找到了这个电话....

事实上,即使是用于进行乘法的策略也可能被删除,因为编译器应该能够计算出你没有使用结果值。添加代码来打印x的值,并从编译时无法知道的某个值中播种x(在这样的小实验程序中使用argc通常很方便,那么你将至少强迫编译器留下功能重要的代码。

  

这个设计是O.K。?

这取决于很多事情(比如你是否想要使用模板,因为实现需要在头文件中公开,是否要处理每个实例化的不同类型...),但是你'正确地重新实现设计。

  

通常,实现一个什么都不做的函数是坏事,因为接口说的是完全不同的东西(subCalculate而不是doNothing),但是在策略的情况下,策略名称清楚地表明函数不会做任何事情。否则我需要做类型特征,比如enable_if等,只是为了排除单个函数调用。

您可能需要仔细考虑您的函数名称... do_any_necessary_calculations()ensure_exclusivity()而不是lock_mutex()after_each_value()而不是print_breaks等。< / p>