调用std::function期间释放其所在std::optional是否符合C++20标准?
在std::function执行期间清除其所在std::optional的行为是否符合C++20标准?
我在C++标准中未找到明确答案,想确认当前操作是否为定义良好的行为。我有一个代表线程的类,其中包含成员std::optional<std::function<void()>> ops;线程空闲时会检查ops是否有值,若有则执行(已做适当锁保护)。我想知道:从当前加载到ops中的function内调用ops.clear()是否属于定义良好的行为?
以下是更具说明性的示例(无线程但保留锁机制):
class ops_t { private: std::mutex mutex; std::optional<std::function<void()>> ops; public: void set_ops(std::function<void()> new_ops) { std::lock_guard guard(mutex); ops = new_ops; } void clear_ops() { std::lock_guard guard(mutex); ops.reset(); } void do_ops() { std::optional<std::function<void()>> ops_local = [this]() // make copy so we don't hold mutex while executing { std::lock_guard guard(mutex); return ops; }(); if(ops_local) (*ops_local)(); } }; int main(void) { ops_t ops; ops.set_ops(std::bind_front(&ops_t::clear_ops, &ops)); ops.do_ops(); // is the sequence of events triggered here well defined by the standard? }
StackOverflow上的相关帖子并未解答我的问题,其Accepted Answer主要讨论对象被删除后的指针问题,而我不存在该问题。此代码编译运行无段错误,但场景特殊,需确认是否符合C++20标准。
结论:该行为是C++20标准下定义良好的
核心依据:
- 执行的是独立的std::function拷贝:在
do_ops中,我们先通过加锁拷贝了成员变量ops到局部变量ops_local,后续执行的是这个局部拷贝的std::function。原成员变量ops中的std::function与局部拷贝是完全独立的对象,前者的销毁(通过reset())不会影响后者的执行。 - std::optional::reset()的合法行为:
std::optional::reset()的作用是销毁其内部包含的对象(若存在),这是标准明确允许的操作,只要被销毁的对象不是当前执行流的直接依赖——这里我们执行的是局部拷贝,原对象的销毁不会干扰正在运行的函数逻辑。 - 无数据竞争:所有对成员变量
ops的访问(拷贝、重置)都通过std::mutex加锁保护,符合C++标准中关于线程安全的要求(即使示例中没有多线程,锁的使用也保证了对ops的操作是原子性的,不存在未定义的并发访问)。
另外,std::function的拷贝语义保证了局部的ops_local持有可调用对象的独立副本(这里是std::bind_front生成的绑定对象的拷贝),所以在执行该副本的过程中,原成员变量中的std::function被销毁,不会对当前执行的函数造成任何影响。
内容的提问来源于stack exchange,提问作者Tyler
相关产品推荐
相关产品推荐

