- 主题:deducing this是lambda coroutine lifetime issue的解决方法吗
你这个不是lambda lifetime的问题吧
MyCoroutine my_coroutine(int a)
{
auto lambda = [a](this auto self) -> MyCoroutine { // <---- good
// auto lambda = [a]() -> MyCoroutine { // <---- bad
std::printf("%d\n", a);
co_return;
};
return lambda();
}
你这个my_coroutine()函数因为没有co_wait/co_return/co_yield,所以本身就是个普通函数,根本就不是coroutine,反而是里面的lambda用了co_return是一个coroutine。
你这个lambda capture了一个普通函数stack上的local variable, 肯定要出问题啊
【 在 allegro 的大作中提到: 】
: 如果lambda返回一个coroutine,并且这个lambda有capture,那一般会有lifetime issue。
: 当lambda被销毁后,它的capture list也没了。
: 所以当返回的coroutine被resume时候,就触发了use-after-free。
: ...................
--
FROM 115.193.191.*
coroutine在被呼叫时会在heap上保存它的input parameter,你的bad定义里,a是被capture的,input parameter是void,所以a不会被保存。在 good定义里,this auto self是input parameter,被保存的时候,a也被保存下来了。
--
FROM 115.193.191.*
所以,我觉得不使用this auto self的情况下,正确的姿势是
MyCoroutine my_coroutine(int a)
{
auto lambda = [](int a) -> MyCoroutine
{
std::printf("%d\n", a);
co_return;
};
return lambda(a);
}
在某种意义上,this auto self就是为了打包把所有的都放进去,但是估计可能会引起更多的heap上的复制工作,影响性能
--
FROM 115.193.191.*
c++23 deducing this
--
FROM 115.193.191.*
这个问题只能说c++23只是一个tick,不是tock版本,很多设计没有考虑全面
你这个问题的本质是,如果coroutine是一个functor,到底哪些算coroutine的state,很明显,在现在的版本里,capture的部分不属于coroutine的state,因为它们是functor struct的data member
c++标准在推进的时候,基本都是先考虑free function情况,再推广到lambda和template上
所以最好的办法就是不要用,等它完善。如果一定要用,比如说对coroutine的signature有要求,你的例子是不对的,因为你return lambda(),是一个promise,如果你本身return lambda的话,你只有打包一层,把需要capture的,用普通lambda capture by value,然后在lambda內部再define and call coroutine lambda
【 在 allegro 的大作中提到: 】
: lambda对一个local变量capture by value没有问题。问题在返回的coroutine被resume时,这个capture自身已经被析构掉了。所以这不是shared_ptr能避免的。
: - 来自 水木社区APP v3.5.7
--
FROM 115.193.191.*
MyCoroutine my_coroutine(int a)
{
auto func_lambda = [a]() -> MyCoroutine
{
return [](int a)->MyCoroutine
{
std::printf("%d\n", a);
co_return;
}(a);
};
return func_lambda();
}
【 在 ziqin 的大作中提到: 】
: 这个问题只能说c++23只是一个tick,不是tock版本,很多设计没有考虑全面
: 你这个问题的本质是,如果coroutine是一个functor,到底哪些算coroutine的state,很明显,在现在的版本里,capture的部分不属于coroutine的state,因为它们是functor struct的data member
: c++标准在推进的时候,基本都是先考虑free function情况,再推广到lambda和template上
: ...................
--
修改:ziqin FROM 115.193.191.*
FROM 115.193.191.*
查了一下c++23 standard,感觉这是compiler的一个bug,或者compiler没有fully comply with c++23
[stmt.return.coroutine] (9.6.4)
This section governs how the state of a coroutine is preserved across suspension points. It explicitly states that all local variables (including lambda captures) are preserved in the coroutine frame.
【 在 ziqin 的大作中提到: 】
: 这个问题只能说c++23只是一个tick,不是tock版本,很多设计没有考虑全面
: 你这个问题的本质是,如果coroutine是一个functor,到底哪些算coroutine的state,很明显,在现在的版本里,capture的部分不属于coroutine的state,因为它们是functor struct的data member
: c++标准在推进的时候,基本都是先考虑free function情况,再推广到lambda和template上
: ...................
--
修改:ziqin FROM 115.193.191.*
FROM 115.193.191.*
开销会大一些,不会大太多,主要还是因为context是存在heap上的,需要动态分配内存。lambda还是在stack上的。
主要还是为了代码可读性,大家写异步代码的时候总还是希望逻辑连贯的,别是是现在异步调用越来越多。
f()
{
# logic 1
# wait 1
# logic 2
# wait 2
}
以往自己写callback的时候,需要自己管理各种context,现在只要管一个coroutine handler就可以了。
【 在 hgoldfish 的大作中提到: 】
: 其实不会。不存在开销大得多这种说法。
: c++20 实现的 stackless coroutine. 相当于在生成函数的时候,额外传入个 context 作为参数而已。和 lambda capture 变量是一样的啊。
:
--
FROM 115.193.214.*