为什么不允许常见的子表达式消除const不成员函数? [英] why not allow common subexpression elimination on const nonvolatile member functions?

查看:139
本文介绍了为什么不允许常见的子表达式消除const不成员函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

C ++的目标之一是允许用户定义的类型与内置类型一样好。这似乎失败的一个地方是在编译器优化。如果我们假设一个常量非成员函数是一个read(对于用户定义的类型)的道德等价物,那么为什么不允许编译器消除对这样的函数的重复调用呢?例如

One of the goals of C++ is to allow user-defined types to behave as nicely as built-in types. One place where this seems to fail is in compiler optimization. If we assume that a const nonvolatile member function is the moral equivalent of a read (for a user-defined type), then why not allow a compiler to eliminate repeated calls to such a function? For example

class C {
...
public:
    int get() const;
}

int main() {
    C c;
    int x{c.get()};
    x = c.get(); // why not allow the compiler to eliminate this call
}

与复制elision的参数相同:当它改变操作语义时,它应该工作于遵循良好的语义实践的代码,并且提供效率/模块性的实质性改进。 (在这个例子中,它显然是愚蠢的,但它变得非常有价值,例如,当函数内联时消除多余的迭代安全检查。)

The argument for allowing this is the same as the argument for copy elision: while it changes the operational semantics, it should work for code that follows good semantic practice, and provides substantial improvement in efficiency/modularity. (In this example it is obviously silly, but it becomes quite valuable in, say, eliminating redundant iterative safety checks when functions are inlined.)

当然不会有意义的是允许返回非const引用的函数,只返回值或const引用的函数。

Of course it wouldn't make sense to allow this for functions that return non-const references, only for functions that return values or const references.

我的问题是是否有一个基本的技术参数这不会同样适用于复制elision。

My question is whether there is a fundamental technical argument against this that doesn't equally apply to copy elision.

注意:只是为了清楚,我不建议编译器看看get()的定义。我说的声明get()本身应该允许编译器清除额外的调用。我不是声称它保留了as-if规则;我声称,正如在复制elision,这是一种情况,我们要允许编译器违反as-if规则。如果你正在编写代码,希望副作用在语义上可见,并且不希望多余的调用被消除,你不应该将你的方法声明为const。

Note: just to be clear, I am not suggesting the compiler look inside of the definition of get(). I'm saying that the declaration of get() by itself should allow the compiler to elide the extra call. I'm not claiming that it preserves the as-if rule; I'm claiming that, just as in copy elision, this is a case where we want to allow the compiler to violate the as-if rule. If you are writing code where you want a side effect to be semantically visible, and don't want redundant calls to be eliminated, you shouldn't declare your method as const.

推荐答案

基于对问题澄清的新答案

C: :get 需要比const更强的注释。就像今天一样,const是一个承诺,该方法不(在概念上)修改对象。它不能保证与全局状态或副作用的交互。

C::get would need a stronger annotation than const. As it stands today, the const is a promise that the method doesn't (conceptually) modify the object. It makes not guarantees about interaction with global state or side effects.

因此,如果新版本的C ++标准划分了as-if规则的另一个异常,为复制elision,仅基于一个方法被标记为const的事实,它会打破很多现有的代码。标准委员会似乎很努力不破坏现有的代码。

Thus if the new version of the C++ standard carved out another exception to the as-if rule, as it did for copy elision, based solely on the fact that a method is marked const, it would break a lot of existing code. The standards committee seems to try pretty hard not to break existing code.

(复制elision可能也打破了一些代码,但我认为它实际上是一个非常狭窄的异常)

(Copy elision probably broke some code, too, but I think it's actually a pretty narrow exception compared to what you're proposing.)

你可能会认为我们应该重新指定一个方法声明的const意味着什么,给它更强的意义。这意味着你不能再有一个 C :: print 方法是const,所以看来这种方法也会破坏很多现有的代码。

You might argue that we should re-specify what const means on a method declaration, giving it this stronger meaning. That would mean you could no longer have a C::print method that's const, so it seems this approach would also break a lot of existing code.

所以我们必须发明一个新的注释,例如 pure_function 。为了达到这个标准,你必须提出它,并可能说服至少一个编译器制造商实现它作为一个扩展,说明它是可行和有用的。

So we would have to invent a new annotation, say pure_function. To get that into the standard, you'd have to propose it and probably convince at least one compiler maker to implement it as an extension to illustrate that it's feasible and useful.

我怀疑增量效用很低。如果你的 C :: get 是微不足道的(没有与全局状态的交互,没有可观察到的副作用),那么你可以在类定义中定义它,用于内联。我相信内联将允许编译器生成代码作为一个pure_function标记的声明(或许甚至更多)的最佳,所以我不会期望pure_function标签的增量的好处足够大,以说服标准委员会,编译器制作者和语言用户采用它。

I suspect that the incremental utility is pretty low. If your C::get were trivial (no interaction with global state and no observable side effects), then you may as well define it in the class definition, thus making it available for inlining. I believe inlining would allow the compiler to generate code as optimal as a pure_function tag on the declaration (and maybe even more so), so I wouldn't expect the incremental benefit of a pure_function tag to be significant enough to convince the standards committee, compiler makers, and language users to adopt it.

原始答案

code> C :: get 可能取决于全局状态,它可能有可观察到的副作用,任何一个都会导致错误的第二次调用。它会违反as-if规则。

C::get could depend on global state and it might have observable side effects, either of which would make it a mistake to elide the second call. It would violate the as-if rule.

问题是编译器在调用站点优化时是否知道这一点。在你写的例子中,只有 C :: get 的声明在作用域中。定义在别处,可能在另一个编译单元。因此,编译器必须在编译和优化调用代码时承担最坏的情况。

The question is whether the compiler knows this at the time it's optimizing at the call site. As your example is written, only the declaration of C::get is in scope. The definition is elsewhere, presumably in another compilation unit. Thus the compiler must assume the worst when it compiles and optimizes the calling code.

现在如果 C :: get 都是微不足道的,在视图中,然后我认为理论上可能的编译器意识到没有副作用或非确定性行为,但我怀疑大多数优化器得到积极。除非 C :: get 被内联,所以我想象分析的路径将呈指数增长。

Now if the definition of C::get were both trivial and in view, then I suppose it's theoretically possible for the compiler to realize there are no side effects or non-deterministic behavior, but I doubt most optimizers get that aggressive. Unless C::get were inlined, I imagine there would be an exponential growth in the paths to analyze.

如果你想跳过整个赋值语句(而不是第二次调用 C :: get ),那么编译器还必须检查赋值运算符副作用和对全球状态的依赖,以确保优化不会违反as-if规则。

And if you want to skip the entire assignment statement (as opposed to just the second call of C::get), then the compiler would also have to examine the assignment operator for side effects and reliance on global state in order to ensure the optimization wouldn't violate the as-if rule.

这篇关于为什么不允许常见的子表达式消除const不成员函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆