以下代码在最新版本的 GCC 和 Clang 中可以正常工作,但会导致 GCC 11 到 GCC 12 中的双重释放,如 https://godbolt.org/z/z66qYaxcG 所示。
#include <coroutine>
#include <iostream>
#include <string>
struct Coro{
struct Promise;
struct Awaiter{
bool await_ready(){return true;}
void await_resume(){}
void await_suspend(std::coroutine_handle<Promise> coro){}
};
struct Promise{
Coro get_return_object(){return {};}
auto initial_suspend() noexcept{return std::suspend_never{};}
auto final_suspend() noexcept{return std::suspend_never{};}
void unhandled_exception(){}
Awaiter await_transform(const Coro&){
return {};
}
void return_void(){}
};
using promise_type = Promise;
};
struct Aggregate{
//(*)
//Aggregate(const std::string& s):s{s}{}
std::string s;
};
static_assert(std::is_aggregate_v<Aggregate>);
Coro f1(Aggregate){
co_return;
}
Coro f2(std::string){
co_return;
}
Coro g(){
std::string foo{"foo"};
// 1.
co_await f1(Aggregate{"/"+foo});
// 2.
//co_await f2("/" + foo);
// 3.
//Coro c = f1(Aggregate{"/"+foo});
//co_await c;
}
int main(){
g();
}
我想知道这是否是由于编译器错误或未定义的行为造成的,在前一种情况下,是否有任何与之相关的错误报告,在后一种情况下,为什么它是未定义的行为。我做了一些实验,发现双重释放在以下任何修改下都会消失,
(*)
的行附近添加用户定义的构造函数,以便 Aggregate
不再是聚合2.
附近的行并调用 f2
)f1
的调用放在与 co_await
不同的行中(取消注释 3.
附近的行)此外,我还观察到,将
f1
更改为通过引用而不是通过值获取参数并不能解决问题。