为啥 C++11 中捕获的变量在捕获中具有不同的值?
Posted
技术标签:
【中文标题】为啥 C++11 中捕获的变量在捕获中具有不同的值?【英文标题】:Why is a captured variable in C++11 of different value inside a capture?为什么 C++11 中捕获的变量在捕获中具有不同的值? 【发布时间】:2020-04-27 10:20:16 【问题描述】:我不知道如何解释这种行为,这里用一个最小的例子来展示。
为什么没有正确捕获size
?
#include <iostream>
#include <vector>
using namespace std;
auto&& matcher1KO = [] (vector<int> &v)
int size = v.size();
cout << "size outside : " << size << "\n"; // print 1
return [&] (bool b)
cout << "v.size() : " << v.size() << "\n"; // print 1
cout << "size inside : " << size << "\n"; // print 0
;
;
auto&& matcher2OK = [] (vector<int> &v)
int size = v.size();
cout << "size outside : " << size << "\n"; // print 1
return [&] ()
cout << "v.size() : " << v.size() << "\n"; // print 1
cout << "size inside : " << size << "\n"; // print 1
;
;
int main()
vector<int> v +1;
auto matcherf1 = matcher1KO(v); //
matcherf1(true);
auto matcherf2 = matcher2OK(v);
matcherf2();
【问题讨论】:
您返回一个 lambda,它通过引用捕获了局部变量size
,并且所述引用变得悬空。您需要按价值捕获。
auto&& matcher1KO
为什么是&&
?
您返回 auto&&
本地的 lambda,这也是未定义的行为。这些闭包的生命周期不会通过将其绑定到返回类型中的引用来延长。
@rafix07 你的意思是matcher1KO
和matcher2OK
是悬空的?他们不绑定到生命周期延长的 lambda 吗?他们绑定的 lambda 按值返回。抱歉,我看不到 UB...
@songyuanyao 你说得对,我看错了这些台词。最外面的 lambda 是纯右值,然后它只是作为全局变量matcher1KO
绑定到右值引用,所以这里一切正常。我收回我之前的评论。
【参考方案1】:
两个代码都有未定义的行为,一切皆有可能。
这两种情况的原因是一样的:变量size
是lambda的operator()
内部的一个局部对象,调用结束时会被销毁。您正在通过引用捕获 size
并且引用被悬空。
将其更改为按值捕获就可以了。例如
return [=] (bool b)
cout << "v.size() : " << v.size() << "\n"; // print 1
cout << "size inside : " << size << "\n"; // print 1
;
【讨论】:
我明白了。为什么编译器不会捕获“未定义的行为”?这真是令人惊讶 @nicolas UB 意味着编译器可以为所欲为;这是程序员的责任。 @nicolas 语言中“存在”未定义行为的全部原因是它涵盖了那些(通常)对于编译器来说太难或不值得花时间的事情诊断。使这些正确是程序员的责任。悬空引用就是这样的教科书案例。 这个 UB 没有任何用处。所以不排除 this UB 是没有意义的。其他一些 UB 可能意味着过于复杂而无法表达或检查编译器。事实并非如此。 @nicolas Clang 对此给出警告。以上是关于为啥 C++11 中捕获的变量在捕获中具有不同的值?的主要内容,如果未能解决你的问题,请参考以下文章
在 Java Lambda 中,为啥在捕获的变量上调用 getClass()
为啥 XCUITest 在 Xcode 11.4.1 中捕获的流失败