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

时间:2015-05-14 19:28:39

标签: c++ optimization const

假设:

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(); }

编译输出提供内存提取以读取xfn0()的值,而添加static会导致在5中内联文字fn1()。这意味着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()直接评估Bar::m内的getget(),我会避免指针间接的级别。如果x是静态的,则无法执行此操作。

我不清楚为什么static是必要的,以便进行此优化。

1 个答案:

答案 0 :(得分:3)

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

非静态const int成员在初始化后无法更改,但编译器很难静态确定它只能有一个可能的值。请注意,仅当该成员没有 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)则可能是其他内容。还要考虑如果该成员被公开会发生什么:

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