局部变量与类变量编译器优化; 工作与不工作

Cha*_*cox 0 c++ variables optimization class local

我有一个代码示例,当结构化为类变量时,直接优化不起作用,但作为局部变量起作用; 我想知道:为什么优化不会发生在类变量公式上?

我的示例代码的目的是让一个类在构造时启用或禁用,并且可能在它的生命周期内更改.我希望,当对象的整个生命周期被禁用时,编译器会优化掉在启用对象时有条件执行的所有代码.

具体来说,我有一个std :: ofstream,我只想在"启用"时写入.禁用时,我希望跳过所有格式化输出.(我真正的课程是自己的,非平凡的消息格式化.)

我发现当我把它表示为一个类时,我没有得到我期望的优化.但是,如果我将代码全部复制为局部变量,我确实看到了预期的行为.

另外,我发现如果我不在示例类的方法体中的任何地方进行std :: ofstream调用,如'open','exceptions'或'clear',我也会得到预期的优化.(但是,我的设计需要在std :: ofstream上进行这样的调用,所以对我来说这是一个没有实际意义的点.)下面的代码使用MACRO DISABLE_OPEN_OFSTREAM_AFTER_CONSTRUCTOR来允许人们尝试这种情况.

我的示例代码使用'asm'表达式将注释插入生成的汇编代码中.如果在程序集中检查编译器的输出,我希望在'disabled-test'注释之间没有汇编.我正在观察'class disabled-test'注释之间的汇编,但是'locals disabled-test'注释之间没有汇编.

输入C++代码:

#include <fstream> // ofstream

#define DISABLE_OPEN_OFSTREAM_AFTER_CONSTRUCTOR 0

class Test_Ofstream
{
public:
    Test_Ofstream( const char a_filename[],
                   bool a_b_enabled )
    #if DISABLE_OPEN_OFSTREAM_AFTER_CONSTRUCTOR
        : m_ofstream( a_filename ),
          m_b_enabled( a_b_enabled )
    {
    }
    #else
        : m_ofstream(),
          m_b_enabled( a_b_enabled )
    {
        m_ofstream.open( a_filename );
    }
    #endif

    void write_test()
    {
        if( m_b_enabled )
        {
            m_ofstream << "Some text.\n";
        }
    }

private:
    std::ofstream m_ofstream;
    bool m_b_enabled;
};

int main( int argc, char* argv[] )
{
    {
        Test_Ofstream test_ofstream( "test.txt", true );
        asm( "# BEGIN class enabled-test" );
        test_ofstream.write_test();
        asm( "# END class enabled-test" );
    }

    {
        Test_Ofstream test_ofstream( "test.txt", false );
        asm( "# BEGIN class disabled-test" );
        test_ofstream.write_test();
        asm( "# END class disabled-test" );
    }

    {
        bool b_enabled = true;
        #if DISABLE_OPEN_OFSTREAM_AFTER_CONSTRUCTOR
        std::ofstream test_ofstream( "test.txt" );
        #else
        std::ofstream test_ofstream;
        test_ofstream.open( "test.txt" );
        #endif
        asm( "# BEGIN locals enabled-test" );
        if( b_enabled )
        {
            test_ofstream << "Some text.\n";
        }
        asm( "# END locals enabled-test" );
    }

    {
        bool b_enabled = false;
        #if DISABLE_OPEN_OFSTREAM_AFTER_CONSTRUCTOR
        std::ofstream test_ofstream( "test.txt" );
        #else
        std::ofstream test_ofstream;
        test_ofstream.open( "test.txt" );
        #endif
        asm( "# BEGIN locals disabled-test" );
        if( b_enabled )
        {
            test_ofstream << "Some text.\n";
        }
        asm( "# END locals disabled-test" );
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出汇编代码:

##### Cut here. #####
#APP
# 53 "test_ofstream_optimization.cpp" 1
        # BEGIN class disabled-test
# 0 "" 2
#NO_APP
        cmpb        $0, 596(%esp)
        je  .L22
        movl        $.LC1, 4(%esp)
        movl        %ebx, (%esp)
.LEHB9:
        call        _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
.LEHE9:
.L22:
#APP
# 55 "test_ofstream_optimization.cpp" 1
        # END class disabled-test
# 0 "" 2
#NO_APP
##### Cut here. #####
#APP
# 116 "test_ofstream_optimization.cpp" 1
        # BEGIN locals disabled-test
# 0 "" 2
# 121 "test_ofstream_optimization.cpp" 1
        # END locals disabled-test
# 0 "" 2
#NO_APP
##### Cut here. #####
Run Code Online (Sandbox Code Playgroud)

我意识到这可能与我正在使用的编译器有关,即:g ++ - 4.6(Debian 4.6.1-4)4.6.1; 编译器标志:-Wall -S -O2.然而,这似乎是一个简单的优化,我发现很难相信它可能是编译器搞砸了.

非常感谢任何帮助,见解或指导.

Pup*_*ppy 5

很简单.当您将代码直接编写为局部变量时,代码将内联,编译器将执行常量折叠.当您在类范围内时,代码未内联且值m_b_enabled未知,因此编译器必须执行调用.为了证明代码在语义上相等并执行此优化,不仅必须内联该调用,而且还必须每次访问该类.编译器可能会认为内联类不会产生足够的好处.编译器也可以选择不内联代码,因为他们不知道如何,并且内联asm表达式正是可能导致他们这样做的事情,因为编译器不知道如何处理汇编代码.

通常,您会放置一个断点并检查反汇编.无论如何,这就是我在Visual Studio中所做的事情.任何类型的内联汇编程序都可能对优化程序造成损害.

当我删除汇编程序表达式时,Visual Studio内联代码 - 并且很快就不执行优化.堆叠优化过程的问题在于,您永远无法获得正确的顺序来查找所有潜在的优化.