【发布时间】:2018-12-06 22:21:46
【问题描述】:
下面的示例代码打印来自 lambda 函数的值,该函数简单地递增并返回静态局部计数器变量的值。
它打印0,1 和2,3 与 gcc 和 C++17 的预期一致。但不是在 Visual Studio Community 2017 15.9.3 中设置了/std:c++17 - 它会打印0,0 和2,3。
#include <iostream>
int main() {
auto f = [] {
static int i = 0;
return i++;
};
const int v1 = f(); // Expect v1 = 0
const int v2 = f(); // Expect v2 = 1
// Prints the wrong values (MSVC 15.9.3 with /std:c++17)
std::cout << v1 << "," << v2 << std::endl; // Expect "0,1", prints "0,0"
// Prints the right values (or ought to with C++17 sequencing, anyway)
std::cout << f() << "," << f() << std::endl; // Expect "2,3", prints "2,3"
return 0;
}
奇怪的输出(在 x86 调试版本中)
0,0
2,3
它看起来像一个编译器错误(所以我们提交了报告):https://developercommunity.visualstudio.com/content/problem/347419/unexpected-return-from-lambda-with-static-local-va.html
生成的程序有什么问题,以至于它错误地为v1 和v2 打印0,但之后正确打印2, 3?任何有根据的猜测编译器错误是什么?
作为一种解决方法,我改用了捕获:
auto f = [i = 0]() mutable {
return i++;
};
更新 - 作为旁注,上面示例的输出在 x86 版本构建中再次不同:
0,1
3,2
MSVC 存在另一个问题,尽管设置了/std:c++17,但std::cout 的<< 运算符没有从左到右排序,我推测这会导致3,2 在这里输出,在最少。
【问题讨论】:
-
你真的认为我们可以解释闭源编译器的内部工作原理吗?
-
两次输入函数不是更好吗?
-
真正奇怪的是,如果您在第一行设置断点
cout自动监视窗口显示v1和v2分别是0和1。 -
查看程序集告诉我们的是,是的,它做错了。
-
@aschepler 好点,我稍微改述了这个问题。
标签: c++ visual-c++ visual-studio-2017 c++17 compiler-bug