F.54: 如果捕获这个,显式捕获所有变量(没有默认捕获)
F.54: If you capture this, capture all variables explicitly (no default capture)
读完后有点困惑Cppcore Guideline F.54
关于 lambda 捕获
"Writing [=] in a member function appears to capture by value, but
actually captures data members by reference "
例子
class My_class {
int x = 0;
// ...
void f() {
int i = 0;
// ...
auto lambda = [=]{ use(i, x); }; // BAD: "looks like" copy/value capture
// [&] has identical semantics and copies the this pointer under the current rules
// [=,this] and [&,this] are not much better, and confusing
x = 42;
lambda(); // calls use(42);
x = 43;
lambda(); // calls use(43);
// ...
auto lambda2 = [i, this]{ use(i, x); }; // ok, most explicit and least confusing
// ...
}
};
为什么这被视为不良
auto lambda = [=]{ use(i, x); };
和下面的一个很好的做法
auto lambda2 = [i, this]{ use(i, x); };
我试过这个例子,但没有看到任何东西 difference.May 因为我没有正确理解这些语句
#include<iostream>
using namespace std;
class My_class {
public:
int x = 0;
// ...
void f() {
int i = 0;
// ...
auto lambda = [=]{ cout<<i<<x<<endl; }; // BAD: "looks like" copy/value capture
// [&] has identical semantics and copies the this pointer under the current rules
// [=,this] and [&,this] are not much better, and confusing
x = 42;
lambda(); // calls use(42);
x = 43;
lambda(); // calls use(43);
// ...
auto lambda2 = [i, this]{ cout<<i<<x<<endl; }; // ok, most explicit and least confusing
lambda2();
}
};
int main()
{
My_class val;
val.f();
}
输出
042
043
043
Program ended with exit code: 0
任何带有示例的方向、指南或解释都会有所帮助
Edit
After few explanation(see the answers below)
created a new example to demonstrate the
behaviour
#include<iostream>
using namespace std;
class My_class {
public:
int x = 0;
// ...
void f() {
int i = 0;
// ...
auto lambda = [=]{ cout<<i<<x<<endl; x=10; }; // BAD: "looks like" copy/value capture
// [&] has identical semantics and copies the this pointer under the current rules
// [=,this] and [&,this] are not much better, and confusing
x = 42;
lambda(); // calls use(42);
cout<<"value of x is "<<x<<endl;
x = 43;
lambda(); // calls use(43);
// ...
auto lambda2 = [i, this]{ cout<<i<<x<<endl; }; // ok, most explicit and least confusing
lambda2();
}
};
int main()
{
My_class val;
val.f();
}
输出
042
value of x is 10
043
010
Program ended with exit code: 0
即使按值捕获,这也会更改外部 x 值
I tried with the example but didn't see any difference.
因为在那个例子中,行为没有区别。然而,该准则之所以在这里,是因为(在其作者看来)可读性存在差异。
也可以考虑
auto lambda3 = [i, this]{ use(i, x++); };
问题是捕获的语义在书面语法中并不明显。语法的含义取决于上下文,阅读和维护起来可能会造成混淆。
如果它不在成员函数内,人们会期望 auto lambda = [=]{ use(i, x); };
制作 x
的 copy,这样如果 x
进行更改,副本仍将保留其原始值。调用 lambda
将始终调用 use(0, 42)
。但是它在成员内部并不是这样的!
你写 =
但得到的行为就像你通过引用捕获一样。代码应该与它的编写方式具有明确和不同的含义。
"Writing [=] in a member function appears to capture by value, but
actually captures data members by reference "
因为无法捕获数据成员。捕获的是 this
.
即使this
被复制捕获,你仍然可以修改所有成员this
,就好像成员被引用捕获一样,它们都是通过this
指针访问的吗才是真正被抓到的。
通过使用 auto lambda2 = [i, this]{ use(i, x); };
,您明确表示 x
未被捕获,但 this
被捕获。
"Writing [=] in a member function appears to capture by value, but actually captures data members by reference "
引用说明了一切,在成员函数中写[=]看似是按值捕获,实际上是按引用捕获数据成员。
一位大人物曾经说过,如果你不必很聪明,那是一件好事。这意味着你应该明确,并使用语言清楚地表达你想要发生的事情。
默认捕获捕获局部范围内的变量。 this->x 不在范围内,但 this 在范围内。因此 x 未被捕获,但 this 被捕获。但是你很可能使用唯一的 x 来表示 this->x.
因此,尽管您订购了按值捕获,但您得到的是按引用捕获。那种东西需要你仔细阅读和集中注意力,可能会让不知情的程序员措手不及。
我稍微更改了示例并添加了更多选项。
[=]
potemkin 捕获,承诺按值捕获所有内容,因此对所有 class 成员产生引用捕获->
[我,这个]
更明确的捕获,承诺按值捕获 i 和 this,因此减少了看到 this->x 将是引用捕获所需的集中程度。
我建议在正文中使用 this->x 而不是 x 以确保完全清楚。
[=, my_copy_of_x = x]
初始捕获语法允许通过值或引用显式捕获 x 所需的任何内容。 &my_copy_of_x = x 会产生引用捕获
[=,my_copy_of_x = 这个->x]
相同,只是更冗长了一点。明确指出 x 是成员而不是局部变量。
[my_i = i, my_copy_of_x = this->x]
这当然也适用于局部变量 i
using namespace std;
class My_class {
public:
int x = 0;
void f() {
int i = 0;
x = 42;
auto lambda1 = [=]{ cout << i << " " << x << endl; };
auto lambda2 = [i,this]{ cout << i << " " << x <<endl; };
auto lambda3 = [=,my_copy_of_x = x]{ cout<<i<<" "<< x << " " << my_copy_of_x << endl; };
auto lambda4 = [=,my_copy_of_x = this->x]{ cout<<i<<" "<< x << " " << my_copy_of_x << endl; };
auto lambda5 = [my_i = i, my_copy_of_x = this->x]{ cout << my_i << " " << my_copy_of_x<<endl;; };
lambda1(); lambda2(); lambda3(); lambda4(); lambda5();
x = 43;
std::cout << "\nx changed\n\n";
lambda1(); lambda2(); lambda3(); lambda4(); lambda5();
}
};
int main()
{
My_class val;
val.f();
}
0 42
0 42
0 42 42
0 42 42
0 42
x changed
0 43
0 43
0 43 42
0 43 42
0 42
问题在于
[=]{ use(i, x); }
实际上是
[=]{ use(i, this->x); }
所以我们按值捕获 this
和 i
,而我们可能错误地认为 x
按值捕获。
[i, this]{ use(i, x); };
更明确。
读完后有点困惑Cppcore Guideline F.54
关于 lambda 捕获
"Writing [=] in a member function appears to capture by value, but actually captures data members by reference "
例子
class My_class {
int x = 0;
// ...
void f() {
int i = 0;
// ...
auto lambda = [=]{ use(i, x); }; // BAD: "looks like" copy/value capture
// [&] has identical semantics and copies the this pointer under the current rules
// [=,this] and [&,this] are not much better, and confusing
x = 42;
lambda(); // calls use(42);
x = 43;
lambda(); // calls use(43);
// ...
auto lambda2 = [i, this]{ use(i, x); }; // ok, most explicit and least confusing
// ...
}
};
为什么这被视为不良
auto lambda = [=]{ use(i, x); };
和下面的一个很好的做法
auto lambda2 = [i, this]{ use(i, x); };
我试过这个例子,但没有看到任何东西 difference.May 因为我没有正确理解这些语句
#include<iostream>
using namespace std;
class My_class {
public:
int x = 0;
// ...
void f() {
int i = 0;
// ...
auto lambda = [=]{ cout<<i<<x<<endl; }; // BAD: "looks like" copy/value capture
// [&] has identical semantics and copies the this pointer under the current rules
// [=,this] and [&,this] are not much better, and confusing
x = 42;
lambda(); // calls use(42);
x = 43;
lambda(); // calls use(43);
// ...
auto lambda2 = [i, this]{ cout<<i<<x<<endl; }; // ok, most explicit and least confusing
lambda2();
}
};
int main()
{
My_class val;
val.f();
}
输出
042
043
043
Program ended with exit code: 0
任何带有示例的方向、指南或解释都会有所帮助
Edit
After few explanation(see the answers below) created a new example to demonstrate the behaviour
#include<iostream>
using namespace std;
class My_class {
public:
int x = 0;
// ...
void f() {
int i = 0;
// ...
auto lambda = [=]{ cout<<i<<x<<endl; x=10; }; // BAD: "looks like" copy/value capture
// [&] has identical semantics and copies the this pointer under the current rules
// [=,this] and [&,this] are not much better, and confusing
x = 42;
lambda(); // calls use(42);
cout<<"value of x is "<<x<<endl;
x = 43;
lambda(); // calls use(43);
// ...
auto lambda2 = [i, this]{ cout<<i<<x<<endl; }; // ok, most explicit and least confusing
lambda2();
}
};
int main()
{
My_class val;
val.f();
}
输出
042
value of x is 10
043
010
Program ended with exit code: 0
即使按值捕获,这也会更改外部 x 值
I tried with the example but didn't see any difference.
因为在那个例子中,行为没有区别。然而,该准则之所以在这里,是因为(在其作者看来)可读性存在差异。
也可以考虑
auto lambda3 = [i, this]{ use(i, x++); };
问题是捕获的语义在书面语法中并不明显。语法的含义取决于上下文,阅读和维护起来可能会造成混淆。
如果它不在成员函数内,人们会期望 auto lambda = [=]{ use(i, x); };
制作 x
的 copy,这样如果 x
进行更改,副本仍将保留其原始值。调用 lambda
将始终调用 use(0, 42)
。但是它在成员内部并不是这样的!
你写 =
但得到的行为就像你通过引用捕获一样。代码应该与它的编写方式具有明确和不同的含义。
"Writing [=] in a member function appears to capture by value, but actually captures data members by reference "
因为无法捕获数据成员。捕获的是 this
.
即使this
被复制捕获,你仍然可以修改所有成员this
,就好像成员被引用捕获一样,它们都是通过this
指针访问的吗才是真正被抓到的。
通过使用 auto lambda2 = [i, this]{ use(i, x); };
,您明确表示 x
未被捕获,但 this
被捕获。
"Writing [=] in a member function appears to capture by value, but actually captures data members by reference "
引用说明了一切,在成员函数中写[=]看似是按值捕获,实际上是按引用捕获数据成员。
一位大人物曾经说过,如果你不必很聪明,那是一件好事。这意味着你应该明确,并使用语言清楚地表达你想要发生的事情。
默认捕获捕获局部范围内的变量。 this->x 不在范围内,但 this 在范围内。因此 x 未被捕获,但 this 被捕获。但是你很可能使用唯一的 x 来表示 this->x.
因此,尽管您订购了按值捕获,但您得到的是按引用捕获。那种东西需要你仔细阅读和集中注意力,可能会让不知情的程序员措手不及。
我稍微更改了示例并添加了更多选项。
[=]
potemkin 捕获,承诺按值捕获所有内容,因此对所有 class 成员产生引用捕获->
[我,这个]
更明确的捕获,承诺按值捕获 i 和 this,因此减少了看到 this->x 将是引用捕获所需的集中程度。
我建议在正文中使用 this->x 而不是 x 以确保完全清楚。
[=, my_copy_of_x = x]
初始捕获语法允许通过值或引用显式捕获 x 所需的任何内容。 &my_copy_of_x = x 会产生引用捕获
[=,my_copy_of_x = 这个->x]
相同,只是更冗长了一点。明确指出 x 是成员而不是局部变量。
[my_i = i, my_copy_of_x = this->x]
这当然也适用于局部变量 i
using namespace std;
class My_class {
public:
int x = 0;
void f() {
int i = 0;
x = 42;
auto lambda1 = [=]{ cout << i << " " << x << endl; };
auto lambda2 = [i,this]{ cout << i << " " << x <<endl; };
auto lambda3 = [=,my_copy_of_x = x]{ cout<<i<<" "<< x << " " << my_copy_of_x << endl; };
auto lambda4 = [=,my_copy_of_x = this->x]{ cout<<i<<" "<< x << " " << my_copy_of_x << endl; };
auto lambda5 = [my_i = i, my_copy_of_x = this->x]{ cout << my_i << " " << my_copy_of_x<<endl;; };
lambda1(); lambda2(); lambda3(); lambda4(); lambda5();
x = 43;
std::cout << "\nx changed\n\n";
lambda1(); lambda2(); lambda3(); lambda4(); lambda5();
}
};
int main()
{
My_class val;
val.f();
}
0 42
0 42
0 42 42
0 42 42
0 42
x changed
0 43
0 43
0 43 42
0 43 42
0 42
问题在于
[=]{ use(i, x); }
实际上是
[=]{ use(i, this->x); }
所以我们按值捕获 this
和 i
,而我们可能错误地认为 x
按值捕获。
[i, this]{ use(i, x); };
更明确。