我已阅读此问答。 C++20 协程的 Lambda 生命周期解释
如果我理解正确的话,如果 lambda 表达式用作协程函数,则捕获某些内容的 lambda 表达式是不安全的。
现在我提出以下问题。
#include <iostream>
#include <boost/asio.hpp>
#include <boost/asio/experimental/co_composed.hpp>
namespace asio = boost::asio;
struct foo {
template <typename CompletionToken>
auto mf1(
CompletionToken&& token
) {
return asio::async_initiate<
CompletionToken,
void()
>(
asio::experimental::co_composed<
void()
>(
[]( // capture nothing
auto /*state*/,
foo& self
) -> void {
// co_await some_async_function(asio::deferred);
self.val_++; // accesses member variables via self
co_return {};
}
),
token,
std::ref(*this)
);
}
template <typename CompletionToken>
auto mf2(
CompletionToken&& token
) {
return asio::async_initiate<
CompletionToken,
void()
>(
asio::experimental::co_composed<
void()
>(
[this]( // capture this.
auto /*state*/
) -> void {
// co_await some_async_function(asio::deferred);
val_++; // accesses member variables
co_return {};
}
),
token
);
}
int val_ = 0;
};
asio::awaitable<void> proc() {
foo f;
co_await f.mf1(asio::deferred);
co_await f.mf2(asio::deferred);
std::cout << f.val_ << std::endl;
co_return;
}
int main() {
asio::io_context ioc;
asio::co_spawn(
ioc.get_executor(),
proc(),
asio::detached
);
ioc.run();
}
godbolt 链接:https://godbolt.org/z/d7snvYYqb
class
foo
有两个成员函数。两个成员函数都做同样的事情。它们是由co_composed
实现的异步函数。
mf1()
的 lambda 表达式没有捕获任何内容,并将 *this
作为 self
传递。 val_
通过 self
访问。我认为这是安全的。
mf2()
的 lambda 表达式捕获此指针。 val_
通过该指针访问。安全吗?
在访问val_
之前,可以放置co_await,这样上下文就可以切换和切换回来。那么这种情况下,捕获的this指针是如何处理的呢?
我怀疑它可能不安全。
使用参考资料的安全性如何?该引用必须指向预期类型的有效对象。
这种情况什么时候才能停止?当所引用对象的生命周期结束时,或者当该对象因其他原因而失效时(例如,通过移动)。
在您的代码中,两者都不适用。
foo
住在Asio的coro框架中,很稳定。
这里至关重要的是
this
指的是 foo
实例,而不是 lambda。 lambda 实例很可能沿着异步调用链移动,因此不能被认为是稳定的。当您有价值捕获并意外传递对它们的引用时,这可能是相关的。幸运的是,您可能不需要 lambda 中的太多状态,因为 foo
实例基本上