11 July 2023

C++ 核心指南目录

“Parameters to coroutines should not be passed by reference”

理由

一旦协程执行到悬挂点,比如 co_wait ,就会从同步代码段返回。在这个点之后,任何通过引用传递的参数都是空悬变量。任何其他地方访问这些引用变量都会产生未定义的行为结果,包括可能会写入自由区内存。

坏例子

std::future<int> Class::do_something(const std::shared_ptr<int>& input)
{
    co_await something();

    // DANGER: the reference to input may no longer be valid and may
    // be freed memory
    co_return *input + 1;
}

好例子

std::future<int> Class::do_something(std::shared_ptr<int> input)
{
    co_await something();
    co_return *input + 1; // input is a copy that is still valid here
}

注意

在悬挂点之前访问引用传递的参数不会出问题。后续对该协程函数的修改,添加或移动悬挂点,就可能又引入这类问题。某些类型的协程会要求悬挂点在第一行代码之前,这时候,访问引用传递的参数都会是不安全的。通过值传递会更安全,因为值传递的参数会在协程框架内一直存在,所以在整个协程内访问值传递的参数都是安全的。

注意

对于传出结果的 output 参数,也存在同样的问题。协程中应该避免 output 参数。

强化

标记所有有引用传递的参数的协程。