gpt4 book ai didi

c++ - C++17 引入的求值顺序保证是什么?

转载 作者:可可西里 更新时间:2023-11-01 18:39:50 25 4
gpt4 key购买 nike

C++17 evaluation order guarantees (P0145) 中投票的含义是什么?在典型的 C++ 代码上?

它对以下内容有何改变?

i = 1;
f(i++, i)

std::cout << f() << f() << f();

f(g(), h(), j());

最佳答案

一些常见情况下,评估顺序迄今尚未未指定,但在 C++17 中已指定且有效。一些未定义的行为现在是未指定的。

i = 1;
f(i++, i)

未定义,但现在未指定。具体而言,未指定的是 f 的每个参数相对于其他参数的评估顺序。 i++ 可能在 i 之前计算,反之亦然。事实上,尽管在同一个编译器下,它可能会以不同的顺序评估第二个调用。

但是,在执行任何其他参数之前,要求完整执行每个参数的评估,并带有所有副作用。因此,您可能会得到 f(1, 1)(第二个参数首先计算)或 f(1, 2)(第一个参数首先计算)。但是你永远不会得到 f(2, 2) 或任何其他类似的东西。

std::cout << f() << f() << f();

未指定,但它将与运算符优先级兼容,以便 f 的第一个评估将在流中排在第一位(下面的示例)。

f(g(), h(), j());

仍然具有未指定的 g、h 和 j 的评估顺序。请注意,对于 getf()(g(),h(),j()),规则规定 getf() 将在 g 之前计算, h, j.

另请注意提案文本中的以下示例:

 std::string s = "but I have heard it works even if you don't believe in it"
s.replace(0, 4, "").replace(s.find("even"), 4, "only")
.replace(s.find(" don't"), 6, "");

该示例来自 The C++ Programming Language,第 4 版,Stroustrup,过去是未指定的行为,但在 C++17 中它将按预期工作。可恢复函数 (.then( . . . )) 也存在类似问题。

作为另一个示例,请考虑以下内容:

#include <iostream>
#include <string>
#include <vector>
#include <cassert>

struct Speaker{
int i =0;
Speaker(std::vector<std::string> words) :words(words) {}
std::vector<std::string> words;
std::string operator()(){
assert(words.size()>0);
if(i==words.size()) i=0;
// Pre-C++17 version:
auto word = words[i] + (i+1==words.size()?"\n":",");
++i;
return word;
// Still not possible with C++17:
// return words[i++] + (i==words.size()?"\n":",");

}
};

int main() {
auto spk = Speaker{{"All", "Work", "and", "no", "play"}};
std::cout << spk() << spk() << spk() << spk() << spk() ;
}

在 C++14 之前,我们可能(并且将会)得到如下结果

play
no,and,Work,All,

代替

All,work,and,no,play

请注意,上面的效果与

相同
(((((std::cout << spk()) << spk()) << spk()) << spk()) << spk()) ;

但是,在 C++17 之前,仍然不能保证第一个调用首先进入流。

引用文献:来自 the accepted proposal :

Postfix expressions are evaluated from left to right. This includesfunctions calls and member selection expressions.

Assignment expressions are evaluated from right to left. Thisincludes compound assignments.

Operands to shift operators are evaluated from left to right. Insummary, the following expressions are evaluated in the order a, thenb, then c, then d:

  1. a.b
  2. a->b
  3. a->*b
  4. a(b1, b2, b3)
  5. b @= a
  6. a[b]
  7. a << b
  8. a >> b

Furthermore, we suggest the following additional rule: the order ofevaluation of an expression involving an overloaded operator isdetermined by the order associated with the corresponding built-inoperator, not the rules for function calls.

编辑说明:我原来的答案误解了a(b1, b2, b3)b1b2b3 的顺序仍未指定。 (感谢@KABoissonneault,所有评论者。)

然而,(正如@Yakk 指出的那样)这很重要:即使 b1b2b3 是非平凡的表达式,在开始评估其他参数之前,它们中的每一个都被完全评估并绑定(bind)到相应的函数参数。标准是这样规定的:

§5.2.2 - Function call 5.2.2.4:

. . .The postfix-expression is sequenced before each expression in theexpression-list and any default argument. Every value computation andside effect associated with the initialization of a parameter, and theinitialization itself, is sequenced before every value computation andside effect associated with the initialization of any subsequentparameter.

但是,the GitHub draft 中缺少其中一个新句子:

Every value computation and side effect associated with theinitialization of a parameter, and the initialization itself, issequenced before every value computation and side effect associatedwith the initialization of any subsequent parameter.

例子。它解决了一个存在数十年之久的问题 ( as explained by Herb Sutter ),异常安全,比如

f(std::unique_ptr<A> a, std::unique_ptr<B> b);

f(get_raw_a(), get_raw_a());

如果其中一个调用 get_raw_a() 在另一个调用之前抛出,将会泄漏原始指针与其智能指针参数相关联。

正如 T.C. 所指出的,该示例存在缺陷,因为原始指针的 unique_ptr 构造是显式的,因此无法编译。*

还要注意这个经典question (标记为 C,而不是 C++):

int x=0;
x++ + ++x;

仍未定义。

关于c++ - C++17 引入的求值顺序保证是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46471806/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com