令人不安的评估顺序

时间:2018-09-06 11:36:44

标签: c++ expression-evaluation

当我使用自己喜欢的容器时,我倾向于连锁经营。例如,在著名的Erase–remove idiom中:

v.erase( std::remove_if(v.begin(), v.end(), is_odd), v.end() );

根据我对求值顺序的了解,v.end()(在rhs上)可能在对std::remove_if的调用之前被评估。这不是问题,因为std::remove*仅对向量进行混洗而不更改其最终迭代器。

但这可能会导致真正令人惊讶的构造,例如(demo):

#include <iostream>

struct Data
{
    int v;
    int value() const { return v; }
};

auto inc(Data& data)           { return ++data.v; }
void print_rhs(int, int value) { std::cout << value << '\n'; }

int main()
{
    Data data{0};
    print_rhs(inc(data), data.value()); // might print 0
}

这是令人惊讶的,因为print_rhs在调用inc之后被称为。这意味着在调用data.v1print_rhs。不过,由于data.value()可能在之前求值,因此0是可能的输出。

如果评估顺序不那么令人惊讶,我认为这可能是一个不错的改进。尤其是如果具有副作用的函数的参数在没有副作用的函数之前进行了评估。

我的问题是:

  • C ++委员会是否曾经讨论或建议过这种改变?
  • 您看到它可能带来的任何问题吗?

1 个答案:

答案 0 :(得分:8)

  

C ++委员会是否曾经讨论或建议过这种改变?

可能。

  

您看到它可能带来的任何问题吗?

是的。它可以减少当今存在的优化机会,并且除了能够编写更多的单行代码之外,没有带来其他直接收益。但是无论如何,单行并不是一件好事,因此,该提议可能永远不会超越-99 points