return C++中局部协程变量的地址是否合法?
Is it legal to return address of local coroutine variable in C++?
如果我 return 本地协程变量的地址,例如通过承诺,是否保证按 C++ 标准工作?考虑一个例子(基于https://www.scs.stanford.edu/~dm/blog/c++-coroutines.html):
#include <coroutine>
#include <iostream>
struct ReturnObject {
struct promise_type {
unsigned * value_ = nullptr;
void return_void() {}
ReturnObject get_return_object() {
return {
.h_ = std::coroutine_handle<promise_type>::from_promise(*this)
};
}
std::suspend_never initial_suspend() { return {}; }
std::suspend_never final_suspend() noexcept { return {}; }
void unhandled_exception() {}
};
std::coroutine_handle<promise_type> h_;
operator auto() const { return h_; }
};
template<typename PromiseType>
struct GetPromise {
PromiseType *p_;
bool await_ready() { return false; }
bool await_suspend(std::coroutine_handle<PromiseType> h) {
p_ = &h.promise();
return false;
}
PromiseType *await_resume() { return p_; }
};
ReturnObject counter()
{
auto pp = co_await GetPromise<ReturnObject::promise_type>{};
for (unsigned i = 0;; ++i) {
pp->value_ = &i; // is it legal?
co_await std::suspend_always{};
}
}
int main()
{
std::coroutine_handle<ReturnObject::promise_type> h = counter();
auto &promise = h.promise();
for (int i = 0; i < 5; ++i) {
std::cout << "counter: " << *promise.value_ << std::endl;
h();
}
h.destroy();
}
https://gcc.godbolt.org/z/P5PMc15qW
在实践中我发现它确实有效,但它真的合法吗?
它在某些情况下可以工作,但这不是编写程序的好方法。指针指向的内存单元可以(并且可能很快)被其他变量覆盖。尝试在循环之前写一些代码(声明一些变量)并再次检查结果。
是的,这是合法的。 counter
的局部变量存储在 h
拥有的动态分配对象中。
存在释放后使用可能性的常见注意事项,即 promise
在 h.destroy()
之后悬挂。
如果我 return 本地协程变量的地址,例如通过承诺,是否保证按 C++ 标准工作?考虑一个例子(基于https://www.scs.stanford.edu/~dm/blog/c++-coroutines.html):
#include <coroutine>
#include <iostream>
struct ReturnObject {
struct promise_type {
unsigned * value_ = nullptr;
void return_void() {}
ReturnObject get_return_object() {
return {
.h_ = std::coroutine_handle<promise_type>::from_promise(*this)
};
}
std::suspend_never initial_suspend() { return {}; }
std::suspend_never final_suspend() noexcept { return {}; }
void unhandled_exception() {}
};
std::coroutine_handle<promise_type> h_;
operator auto() const { return h_; }
};
template<typename PromiseType>
struct GetPromise {
PromiseType *p_;
bool await_ready() { return false; }
bool await_suspend(std::coroutine_handle<PromiseType> h) {
p_ = &h.promise();
return false;
}
PromiseType *await_resume() { return p_; }
};
ReturnObject counter()
{
auto pp = co_await GetPromise<ReturnObject::promise_type>{};
for (unsigned i = 0;; ++i) {
pp->value_ = &i; // is it legal?
co_await std::suspend_always{};
}
}
int main()
{
std::coroutine_handle<ReturnObject::promise_type> h = counter();
auto &promise = h.promise();
for (int i = 0; i < 5; ++i) {
std::cout << "counter: " << *promise.value_ << std::endl;
h();
}
h.destroy();
}
https://gcc.godbolt.org/z/P5PMc15qW
在实践中我发现它确实有效,但它真的合法吗?
它在某些情况下可以工作,但这不是编写程序的好方法。指针指向的内存单元可以(并且可能很快)被其他变量覆盖。尝试在循环之前写一些代码(声明一些变量)并再次检查结果。
是的,这是合法的。 counter
的局部变量存储在 h
拥有的动态分配对象中。
存在释放后使用可能性的常见注意事项,即 promise
在 h.destroy()
之后悬挂。