Ser*_*nik 6 c++ asynchronous undefined-behavior language-lawyer
前段时间我正在寻找一种std::async无需存储即可调用的方法std::future,从而不会在作用域末尾阻塞执行。我发现这个答案使用捕获std::shared_ptr的std::future,因此允许对 进行非阻塞调用std::async。
推迟析构函数调用的另一种方法是完全阻止它被调用。这可以通过就地构造来实现operator new。
考虑使用静态线程本地存储进行就地构造的这个版本std::future<void>:
template <class F>
void call_async(F&& fun) {
thread_local uint8_t buf[sizeof(std::future<void>)] = {0};
auto fut = new(buf) std::future<void>();
*fut = std::async(std::launch::async, [fun]() {
fun();
});
}
Run Code Online (Sandbox Code Playgroud)
这个版本不会产生任何与堆分配相关的开销,但它似乎非常非法,虽然我不确定为什么特别。
我知道在构造对象之前使用它是 UB,但事实并非如此。我不确定为什么delete在这种情况下不调用会在 UB 中解决(对于堆分配,它不是 UB)。
我看到的可能问题:
std::promise我想是内部的)更新
每次调用移动分配时,直接在静态存储中构造一个对象(如 IlCapitano 所述)将阻塞(共享状态将被破坏,阻塞已删除对它的最后一个引用的线程)。
由于未释放对共享状态的引用,不调用析构函数会导致泄漏。
在不调用其析构函数的情况下结束非平凡对象的生命周期是未定义的行为,一旦有第二次call_async调用就会发生这种情况。
如果唯一的选择是未定义的行为,那么“与堆分配相关的开销”是用词不当。future回来的人必须async住在某个地方。
更新后的代码已定义行为:它等待上一个调用完成,然后再启动下一个调用。
| 归档时间: |
|
| 查看次数: |
157 次 |
| 最近记录: |