G++;:移动到另一个翻译单元时,会中断“;常数优化“;? 我正在演示演示各种C++优化的演示文稿,并坚持一个例子,代码< > const 允许它们。

G++;:移动到另一个翻译单元时,会中断“;常数优化“;? 我正在演示演示各种C++优化的演示文稿,并坚持一个例子,代码< > const 允许它们。,c++,gcc,C++,Gcc,考虑以下代码: object.h 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 { r

考虑以下代码:

object.h

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);
    }
};
但是,当我将
calculate()
移动到一个单独的翻译单元时,它会强制提取两次
i1
i2
(在
o.calculate()之前和之后。首先
):

mov(%rsp),%esi
mov 0x4(%rsp),%r14d
mov$0x601080,%edi
callq 0x400740
我看不出有什么区别,因为
getI1()
不依赖于
calculate()
可以产生的任何副作用,而且
对象
即使在
calculate()
位于单独的翻译单元中,也应该是常量

是G++不够聪明,还是在这种情况下不适合执行优化?我推测它可以缓存
getI1()
getI2()
来自该答案的调用:

我使用gcc版本4.8.1。我试过-Os和-O2



在这种情况下,
const
似乎没有在GCC优化器中使用。相反,它自己进行挖掘(不能在不同的翻译单元中执行),并搜索。函数可以手动标记为
\uuuuu属性((const))
。消除额外的
getI*()
调用的阶段称为FRE(完全冗余消除)。

要准确回答您的问题,必须了解编译器的实现细节。我不知道,所以接下来的只是猜测

Object::i1
Object::i2
未声明常量。因此,编译器在没有看到
Object::calculate
的定义的情况下,不得不假定它们可能会更改

Object::calculate
本身是常量并不妨碍它更改为
Object::i1
Object::i2
。考虑下面稍微修改的例子:

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

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

    std::pair<int, int> calculate() const;
};

std::pair<int, int> Object::calculate() const {
    (*p1)++;
    return std::pair<int, int>(i1 + i2, i1 * i2);
}
类对象{
int i1;
int i2;
int*p1;
公众:
对象(inti1,inti2):i1(i1),i2(i2),p1(&i1){
int getI1()常量{return i1;}
int getI2()常量{return i2;}
std::pair calculate()常量;
};
std::pair Object::calculate()常量{
(*p1)++;
返回std::pair(i1+i2,i1*i2);
}

此外,
o
一开始并没有被声明为常量,因此
Object::calculate
有权做一些像
const\u cast
一样粗鲁的事情,并逍遥法外

要准确回答您的问题,必须了解编译器的实现细节。我不知道,所以接下来的只是猜测

Object::i1
Object::i2
未声明常量。因此,编译器在没有看到
Object::calculate
的定义的情况下,不得不假定它们可能会更改

Object::calculate
本身是常量并不妨碍它更改为
Object::i1
Object::i2
。考虑下面稍微修改的例子:

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

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

    std::pair<int, int> calculate() const;
};

std::pair<int, int> Object::calculate() const {
    (*p1)++;
    return std::pair<int, int>(i1 + i2, i1 * i2);
}
类对象{
int i1;
int i2;
int*p1;
公众:
对象(inti1,inti2):i1(i1),i2(i2),p1(&i1){
int getI1()常量{return i1;}
int getI2()常量{return i2;}
std::pair calculate()常量;
};
std::pair Object::calculate()常量{
(*p1)++;
返回std::pair(i1+i2,i1*i2);
}

此外,
o
一开始并没有被声明为常量,因此
Object::calculate
有权做一些像
const\u cast
一样粗鲁的事情,并逍遥法外

要准确回答您的问题,必须了解编译器的实现细节。我不知道,所以接下来的只是猜测

Object::i1
Object::i2
未声明常量。因此,编译器在没有看到
Object::calculate
的定义的情况下,不得不假定它们可能会更改

Object::calculate
本身是常量并不妨碍它更改为
Object::i1
Object::i2
。考虑下面稍微修改的例子:

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

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

    std::pair<int, int> calculate() const;
};

std::pair<int, int> Object::calculate() const {
    (*p1)++;
    return std::pair<int, int>(i1 + i2, i1 * i2);
}
类对象{
int i1;
int i2;
int*p1;
公众:
对象(inti1,inti2):i1(i1),i2(i2),p1(&i1){
int getI1()常量{return i1;}
int getI2()常量{return i2;}
std::pair calculate()常量;
};
std::pair Object::calculate()常量{
(*p1)++;
返回std::pair(i1+i2,i1*i2);
}

此外,
o
一开始并没有被声明为常量,因此
Object::calculate
有权做一些像
const\u cast
一样粗鲁的事情,并逍遥法外

要准确回答您的问题,必须了解编译器的实现细节。我不知道,所以接下来的只是猜测

Object::i1
Object::i2
未声明常量。因此,编译器在没有看到
Object::calculate
的定义的情况下,不得不假定它们可能会更改

Object::calculate
本身是常量并不妨碍它更改为
Object::i1
Object::i2
。考虑下面稍微修改的例子:

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

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

    std::pair<int, int> calculate() const;
};

std::pair<int, int> Object::calculate() const {
    (*p1)++;
    return std::pair<int, int>(i1 + i2, i1 * i2);
}
类对象{
int i1;
int i2;
int*p1;
公众:
对象(inti1,inti2):i1(i1),i2(i2),p1(&i1){
int getI1()常量{return i1;}
int getI2()常量{return i2;}
std::pair calculate()常量;
};
std::pair Object::calculate()常量{
(*p1)++;
返回std::pair(i1+i2,i1*i2);
}
此外,
o
一开始并没有被声明为常量,因此
Object::calculate
有权做一些像
const\u cast
一样粗鲁的事情,并获得awa
// 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;