
"C++" spelled as-is can result in unexpected rendering, such as C++20 was released before C++17 renders as C20 was released before C17 Make consistent use of `[source,cpp]`.
57 lines
1.9 KiB
Plaintext
57 lines
1.9 KiB
Plaintext
== Why is this an issue?
|
|
|
|
Coroutines, introduced in {cpp}20, are functions in which execution can be suspended and resumed.
|
|
When a coroutine resumes, it takes over where it left thanks to the coroutine state.
|
|
|
|
A _coroutine state_ is an object which contains all the information a coroutine needs to resume its execution correctly:
|
|
local variables, copy of the parameters...
|
|
|
|
This means that if a coroutine has a parameter that is a reference to an object, this object must exist as long as the coroutine is not destroyed.
|
|
Otherwise, the reference stored in the _coroutine state_ will become a dangling reference and will lead to undefined behavior when the coroutine resumes.
|
|
|
|
The issue is raised for all coroutine parameters with reference-to-const semantics
|
|
(such as a `const` reference, a `std::string_view`, or a `std::span` with `const` elements)
|
|
that might be used after the coroutine is suspended.
|
|
|
|
To fix the issue, you can either pass the parameter by value,
|
|
or not use the parameter after the first suspension point (`co_await`, `co_yield`, or `initial_suspend`).
|
|
|
|
=== Noncompliant code example
|
|
|
|
[source,cpp]
|
|
----
|
|
generator<char> spell(const std::string& m) { // Noncompliant
|
|
for (char letter : m) {
|
|
co_yield letter;
|
|
}
|
|
}
|
|
|
|
void print() {
|
|
for (char letter : spell("hello world")) { // Here the parameter "m" binds to a temporary
|
|
std::cout << letter << '\n'; // and becomes dangling on the next iteration
|
|
}
|
|
}
|
|
----
|
|
|
|
=== Compliant solution
|
|
|
|
[source,cpp]
|
|
----
|
|
generator<char> spell(const std::string m) { // Compliant: take the argument by copy
|
|
for (char letter : m) {
|
|
co_yield letter;
|
|
}
|
|
}
|
|
|
|
void print() {
|
|
for (char letter : spell("hello world")) {
|
|
std::cout << letter << '\n';
|
|
}
|
|
}
|
|
----
|
|
|
|
=== Exceptions
|
|
|
|
This rule does not raise an issue for `std::reference_wrapper` parameters
|
|
taking it as a witness of the care taken to prevent the reference to become dangling.
|