为什么优化器不优化这段代码?

Why doesn't the optimizer optimize this code?

使用最大优化设置编译和运行此代码似乎给出了相同的结果。

#include <stdio.h>

class A
{
public:
    A() { }
    const int* begin() const { return a; };
    const int* end() const { printf("end\n"); return a + 3; };
    bool isTrue() const { return true; }
    int a[4];
};

const A a{};

class B
{
public:
  const A& operator[](size_t) const { printf("B called\n"); return a; }
};


int main()
{
    const B b{};
    if (!b[0].isTrue()) return -1;
    for (const auto& x : b[0]) printf("%d\n", x);
}

我在 B 类型的常量对象上调用 b[0] 两次,其中 operator[] return 是 A 类型的常量对象。

为什么“B called”被打印了两次?为什么代码不能在旁边保存 b[0] 而在其上保存 运行 不同的功能? (由于函数是 const 函数,它们将 return 相同的结果...)

Why does "B called" get printed twice?

对于初学者来说,因为您在 main 中引用了两次 b[0]。并且由于运算符函数中的 printf 语句指示访问 b[0] 存在副作用。因此编译器不能假定您的 printf 仅用于调试 - 它必须为每次调用调用一次。

使用 godbolt,如果我们删除 printf 语句并进行评估,我们可以看到代码经过大量优化,无需任何调用即可打印 3 次 0

优化:https://godbolt.org/z/E8czPdr5W

operator[] 和其他函数一样是普通函数,由于 C++ 没有纯函数的概念,编译器必须假设每个函数都有副作用。其中一个副作用是您的 printf 调用。如果您 优化 取消对 operator[] 的调用之一,您的程序行为可能会改变(这里它只会打印一次而不是两次)。想象一下,您将调用数据库或其他重要的东西而不是 printf。如果它只是优化,那就太糟糕了。

另请注意,const 成员函数与纯函数不同。 const 表示它不能修改您调用成员函数的实例,但您仍然可以更改全局变量。而且您甚至不能保证 const 成员函数不会更改实例的状态,因为您可以在某些条件下丢弃 const