如何避免在调用异步函数进行 lambda 回调时出现额外的副本

how to avoid the extra copy when calling async function taking a lambda callback

本文关键字:副本 回调 lambda 调用 何避免 异步 函数      更新时间:2023-10-16

我有一个异步函数foo_async,它接受回调(lambda)并在按值捕获后在新线程上执行它。

void foo_async(const std::function<void()>& callback)
{
    std::thread t([callback]() // capture callback by value
    {
        callback();
    });
    t.detach();
}

我在函数bar中使用它,它本身需要回调

void bar(const std::function<void()>& callback)
{    
    auto barCallback = [callback] // capture original callback by value
    { 
        callback();
        std::cout << "world" << std::endl; 
    };
    foo_async(barCallback);
}

最后,我从main中调用bar

int main()
{
    std::string s("hello ");
    bar([s]{ std::cout << s; }); // capture some state
    std::cin.get();
}

我遇到的问题是main中的字符串s被复制了三次,一次在main,一次在bar,一次在foo_async。但理想情况下,只需要复制它两次 - main将其放入 lambda 中,foo_async在另一个线程上执行。应该避免bar中的复制,因为它是同步执行的。

有什么方法可以避免s的额外副本吗?请注意,我无法通过 bar 中的引用捕获原始回调,因为foo_async需要在新线程上执行它。

你可以尝试两件事:1)不要保留lambda的本地副本,2)将函数对象移动到lambdas中:

void foo_async(std::function<void()> callback)
{
    std::thread([c = std::move(callback)]() { c(); }).detach();
}
void bar(std::function<void()> callback)
{    
    foo_async([c = std::move(callback)]() { c(); std::cout << "worldn"; });
}
int main()
{
    std::string s("hello ");
    bar([s = std::move(s)]{ std::cout << s; });
}