Avoiding Dangling References
Learn to prevent dangling coroutine references through parameter passing, member functions, lambdas, and guidelines.
The fact that a coroutine can be passed around in our code means that we need to
be very careful about the lifetime of parameters we pass to a coroutine to avoid dangling references. The coroutine frame contains copies of the objects that normally live on the stack, such as local variables and parameters passed to the coroutine. If
a coroutine accepts an argument by reference, the reference is copied, not the object. This means that we can easily end up with dangling references when following the usual guidelines for function parameters; that is, pass objects that are expensive to copy by reference to const
.
Passing parameters to coroutines
The following coroutine uses a reference to a const std::string
:
auto coroutine(const std::string& str) -> Resumable {std::cout << str;co_return;}
Suppose we have a factory function that creates and returns the coroutine, like this:
auto coro_factory() {auto str = std::string{"ABC"};auto res = coroutine(str);return res;}
And finally, a main()
function that uses the coroutine:
int main() {auto coro = coro_factory();coro.resume();}
This code exhibits undefined behavior as the std::string
object containing the
string "ABC"
is no longer alive when the coroutine tries to access it. Hopefully, this doesn’t come as a surprise to us. This problem is similar to having a lambda capture a variable by reference, and then passing the lambda to some other code without keeping the referenced object alive. A similar example can be achieved when passing around a lambda capturing variables by reference:
auto lambda_factory() {auto str = std::string{"ABC"};auto lambda = [&str]() { // Capture str by referencestd::cout << str;};return lambda; // Ops! str in lambda becomes} // a dangling referenceint main() {auto f = lambda_factory();f(); // Undefined behavior}
As we can see, the same problem can happen with lambdas. In the “Essential C++ Techniques” chapter, we warned you about capturing references with lambdas, and it is usually better to avoid this by capturing by value instead.
The solution to avoid ...