为什么const类成员必须是静态的才能进行适当的优化

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

本文关键字:优化 静态 const 成员 为什么      更新时间:2023-10-16

给定:

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会导致文本5fn1()中内联。这意味着,只有当整数常量是静态的时,get()的调用方才能被优化,就好像它使用常量代替get()一样。

我有更复杂的情况,static不合适。派生类通过构造函数将x初始化为不同的值;但是对于这些类中的每一个,x是常数,并且这些类方法可以被优化,就像前面的static的情况一样,如果仅get()被评估为真常数的话。

事实上,我最常见的情况是初始化基类中的引用:

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有必要进行这种优化。

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

非静态const int成员在初始化后不能更改,但编译器更难静态地确定它只能有一个可能的值。请注意,只有当非静态数据成员没有mem初始值设定项时,才使用该成员的大括号或相等初始值设定值。这意味着,例如,如果你有这个:

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),则它可以是其他东西。还要考虑如果成员被公开会发生什么:

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是静态数据成员那样容易。编译器实现者很可能根本就不想写这样的优化。