当一个本地对象被异步函数引用时,它的生命周期与函数不一定同步。如果本地对象的生命周期在异步函数完成之前结束了,那么函数将无法正常工作。所以,本地对象的异步/等待引用捕获并不总是安全的。
为了避免这种情况,可以使用lambda表达式来捕获本地对象的引用。这样,在异步函数完成之前,本地对象的生命周期可以得到保证。
例如:
#include
#include
#include
class Foo {
public:
Foo() { std::cout << "Foo constructed!" << std::endl; }
~Foo() { std::cout << "Foo destructed!" << std::endl; }
void bar() { std::cout << "bar called!" << std::endl; }
};
int main() {
Foo foo;
// unsafe async function
std::async([&]() {
std::cout << "async called!" << std::endl;
foo.bar();
});
// safe async function
std::async([&foo]() {
std::cout << "async called!" << std::endl;
foo.bar();
});
std::cout << "press any key to exit..." << std::endl;
getchar();
return 0;
}
在上面的示例中,我们定义了一个Foo类,并在main函数中创建了一个Foo对象foo。然后,我们定义了两个异步函数,分别通过lambda表达式捕获foo对象的引用和通过参数传递foo对象的引用。第一个异步函数是不安全的,因为它通过引用捕获foo对象,当异步函数执行时,可能会遇到访问已经销毁的对象的问题。第二个异步函数是安全的,因为它通过值捕获foo对象,并在异步函数执行期间保证了foo对象的生命周期。
因此,为了确保异步/等待函数的安全,应该使用lambda表达式并通过值传递本地对象的引用。