我正在进行演示,演示各种C ++优化,并附有const允许它们的示例。

考虑以下代码:

对象

class Object {
    int i1;
    int i2;
public:
    Object(int i1_, int i2_) : i1(i1_), i2(i2_) {}

    int getI1() const { return i1; }
    int getI2() const { return i2; }

    std::pair<int, int> calculate() const {
        return std::pair<int, int>(i1 + i2, i1 * i2);
    }
};


constopt.cpp

#include <iostream>
#include "object.h"

int main() {
    Object o(10, 20);

    std::cout << o.getI1() << " + " << o.getI2()  << " = "
                << o.calculate().first << std::endl
            << o.getI1() << " * " << o.getI2()  << " = "
                << o.calculate().second << std::endl;

    return 0;
}


内联calculate()时,一切正常,G ++将常量(10和20)直接传递给operator <<缓存getI1()getI2()调用:

mov    $0xa,%esi
mov    $0x601080,%edi
callq  0x400740 <_ZNSolsEi@plt>


但是,当我将calculate()移到一个单独的翻译单元时,它会强制将i1i2提取两次(在o.calculate().first之前和之后):

mov    (%rsp),%esi
mov    0x4(%rsp),%r14d
mov    $0x601080,%edi
callq  0x400740 <_ZNSolsEi@plt>


我看不出有什么区别,因为getI1()不依赖于calculate()可能产生的任何副作用,并且即使Object在单独的翻译单元中,calculate()仍应是const。

在这种情况下,G ++是否不够智能或没有资格执行优化?我推测它可以缓存getI1(),而getI2()调用来自该答案:How does const after a function optimize the program?

我使用的是gcc版本4.8.1。我已经尝试了-Os和-O2。



在这种情况下,似乎在GCC优化器中未使用const。相反,它会进行自己的挖掘(无法在不同的翻译单元中执行),并搜索pure and const functions。可以使用__attribute__((const))手动标记功能。消除多余的getI*()调用的阶段称为FRE(完全冗余消除)。

最佳答案

因为getI1()不依赖可通过calculate()创建的任何副作用


不管是否做,C ++标准都未指定。

即使在调用getI1()之前将getI2()calculate()写入流中,在C ++中,函数参数的求值顺序也未指定。这意味着在对calculate()进行任何实际写入之前,允许编译器以任何顺序对getI1()getI2()std::cout进行所有调用。如果它决定在调用calculate()getI1()之前对getI2()进行一次或两次调用,则不能假定i1i2的值未更改。

如果拆分表达式,则编译器应该能够看到i1i2在调用calculate()之前不能更改:

// this statement uses i1 and i2 before they can possibly be changed
std::cout << o.getI1() << " + " << o.getI2()  << " = ";

// this statement might mutate i1 and i2
std::cout << o.calculate().first << std::endl
        << o.getI1() << " * " << o.getI2()  << " = "
            << o.calculate().second << std::endl;



  即使在单独的转换单元中有calculate()的情况下,Object也是常量。


但是您实际上并没有声明oconst

调用const成员函数并不能保证不能更改成员,这更多是调用方与函数之间的非正式合同,而不是保证。

关于c++ - G++:转移到另一个翻译单元会破坏“常量优化”吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/29419563/

10-09 08:56