[英]C++ lambda capture list by value or by reference doesn't give me different results
I am having the below code :我有以下代码:
std::vector<std::function<void()>> functors;
class Bar
{
public :
Bar(const int x, const int y):d_x(x),d_y(y){}
~Bar(){
cout << "Destructing Bar" << endl;
}
void addToQueue()
{
const auto job = [=](){
cout << "x:" << d_x << " y: " << d_y;
};
functors.push_back(job);
}
private :
int d_x,d_y;
};
void example()
{
cout << "Hello World" << endl;
{
shared_ptr<Bar> barPtr = make_shared<Bar>(5,10);
barPtr->addToQueue();
}
cout << "Out of scope. Sleeping" << endl;
usleep(1000);
functors[0]();
}
The output is as expected :输出如预期:
Hello World
Destructing Bar
Out of scope. Sleeping
x:5 y: 10
I am now capturing by value, which is why I assume when the Bar object gets destroyed, I can still access its member variables.我现在按值捕获,这就是为什么我假设当 Bar 对象被破坏时,我仍然可以访问它的成员变量。 If the above is right, I am expecting the below change to give me UB:如果以上是正确的,我期待下面的改变给我 UB:
const auto job = [&](){
However, I still see the same result.但是,我仍然看到相同的结果。 Why is that?这是为什么? Have i understood something wrong?我理解错了吗?
EDIT Further on the above, what I want to understand from this example - is how can I have access to a class member variables in a lambda function even if object has been destroyed?编辑在上面进一步,我想从这个例子中理解 - 即使对象已被破坏,我如何才能访问 lambda 函数中的类成员变量? I am trying to avoid UB and thought that passing by value is the way to go, but can't prove that the opposite isn't working.我试图避免 UB,并认为按价值传递是要走的路,但不能证明相反的方法行不通。
This kind of confusion iss probably one of the reasons why C++20 deprecated the implicit capture of this
with [=]
.这种混淆可能是 C++20 弃用使用[=]
隐式捕获this
的原因之一。 You can still capture [this]
, in which case you have the usual lifetime issues with an unmanaged pointer.您仍然可以捕获[this]
,在这种情况下,非托管指针通常会出现生命周期问题。 You can capture [*this]
(since C+=17), which will capture a copy of *this
so you don't have lifetime issues.您可以捕获[*this]
(自 C+=17 起),这将捕获*this
的副本,因此您不会遇到生命周期问题。
You could also use std::enable_shared_from_this
since you're using a std::shared_ptr
in example
, but that's a bit more complicated.您也可以使用std::enable_shared_from_this
,因为您在example
中使用了std::shared_ptr
,但这有点复杂。 Still, it would avoid both the copy and the UB when the lifetime issues.尽管如此,当生命周期出现问题时,它会避免复制和 UB。
In these examples you are capturing this
and not any of the fields.在这些示例中,您正在捕获this
而不是任何字段。
When capturing this
, by design, it is never captured by copying the object or the fields.在捕获this
时,根据设计,它永远不会通过复制对象或字段来捕获。
The best way to capture a field by value is:按值捕获字段的最佳方法是:
[field = field] () { }
Both versions of your code have undefined behaviour.您的代码的两个版本都有未定义的行为。 barPtr
is the only owner of the shared_ptr
so your object is destructed at the end of the scope containing barPtr
. barPtr
是shared_ptr
的唯一所有者,因此您的对象在包含barPtr
的范围的末尾被破坏。 Executing the lambda which has captured this
from the object in barPtr
has undefined behaviour.执行从barPtr
中的对象捕获this
lambda 具有未定义的行为。
The usual way to prevent this is for the lambda to capture a shared_pointer
from shared_from_this to keep the object alive.防止这种情况的常用方法是让 lambda 从shared_from_this捕获一个shared_pointer
以保持对象处于活动状态。 Eg:例如:
#include <vector>
#include <functional>
#include <iostream>
#include <memory>
std::vector<std::function<void()>> functors;
class Bar : public std::enable_shared_from_this<Bar>
{
public :
Bar(const int x, const int y):d_x(x),d_y(y){}
~Bar(){
std::cout << "Destructing Bar\n";
}
void addToQueue()
{
auto self = shared_from_this();
const auto job = [this, self](){
std::cout << "x:" << d_x << " y: " << d_y << "\n";
};
functors.push_back(job);
}
private :
int d_x,d_y;
};
int main()
{
std::cout << "Hello World\n";
{
std::shared_ptr<Bar> barPtr = std::make_shared<Bar>(5,10);
barPtr->addToQueue();
}
std::cout << "Out of scope\n";
functors[0]();
}
By capturing self
the shared_ptr
will now survive for at least as long as the lambda does.通过捕获self
, shared_ptr
现在将至少与 lambda 一样存活。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.