为什么 const class 成员必须是静态的才能正确优化?

Why must const class members be static to be properly optimised?

给定:

class Foo {        const int x = 5; public: inline int get() { return x; } };
class Bar { static const int x = 5; public: inline int get() { return x; } };
int fn0(Foo& f) { return f.get(); }
int fn1(Bar& b) { return b.get(); }

编译后的输出提供内存提取以读取 fn0()x 的值,而添加 static 会导致文字 5 内联 fn1() ].这意味着 get() 的调用者可以被优化,就好像它使用常量代替 get() 只有当整数常量是静态的。

我有更复杂的情况,static 是不合适的。 Derived classes 通过构造函数将 x 初始化为不同的值;但是对于每个 classes x 是一个常量,并且可以优化那些 class 方法,就像前面的 static 案例一样,如果只评估 get()到一个真正的常数。

事实上,我最常见的情况是在基 class:

中初始化引用
class Foo { int& x; public: Foo(int& init) : x(init) {} inline int get() { return x; } };
class Bar : public Foo { int m; public: Bar() : Foo(m) {} inline int getget() { return get(); };
int fn1(Bar& b) { return b.getget(); }

在这里,如果 get()getget() 中直接评估为 Bar::m,我会避免指针间接级别。如果 x 是静态的,这将不可能。

我不清楚为什么需要 static 才能进行此优化。

在-class中初始化的static const int成员是一个真正的常量表达式,即编译时常量。

非静态const int成员在初始化后不能更改,但编译器很难静态地确定它只能有一个可能的值。请注意,非静态数据成员的 brace-or-equal-initializer 仅在该成员没有 mem-initializer 时才使用.这意味着如果例如你有这个:

class Foo {
    const int x = 5;
  public:
    inline int get() { return x; }
    Foo() = default;
    Foo(int x) : x(x) {}
};

那么 Foo::x 可能是 5,如果默认构造函数被调用,或者它可能是其他东西,如果 Foo::Foo(int) 被调用。还要考虑如果成员是 public:

会发生什么
class Foo {
  public:
    const int x = 5;
    inline int get() { return x; }
};

现在可以使用聚合初始化:

Foo f {42};
// f.x is 42

在您写的 Foo 的特殊情况下,我相信 Foo::x 确实只能是 5,但对于编译器将其确定为如果 Foo::x 是静态数据成员。很可能编译器实现者根本懒得写这样的优化。