我有一个问题,但我似乎无法在标准中找到明确的答案。我想知道我在这里所做的事情是否定义明确(因此可以信赖)
我有一个代表线程的类,并且在该类中有一个成员
std::optional<std::function<void()>> ops;
每隔一段时间,当线程不忙于执行其他代码时,它会检查
ops
是否有值,如果有,则会执行它。 (适当锁定)。
我想知道的是:从当前加载到
ops.clear()
的函数中调用 ops
是否是明确定义的行为。
这是一个更具说明性的示例,没有线程但仍保持锁定:
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?
}
发布在通话期间自毁std::function并没有回答我的问题。那里接受的答案与指向被删除对象的指针有很大的分歧;不过我没有这个问题。
编译此代码有效并运行它不会导致分段错误;然而这种情况相当奇怪,因此我试图确认它是由 c++20 标准很好定义的
您的代码没有按照您的想法进行操作。
您的代码创建 std 函数的堆栈本地副本,然后运行它。运行它时,它会保存 fubction 对象的类副本(在选项中)。
这两个对象是不相关的(嗯,一个是另一个的副本),因此不存在生命周期问题。
所以您发布的代码是安全的。
如果您确实按照其余问题的要求进行操作,我相信您的代码将超出 tge 标准定义行为的范围。
我上次检查过,std 函数不保证它在其拥有的
operator()
运行后不会触及自己的状态。也许可以做出这样的保证,但措辞会很尴尬。
因此,大多数(但不是全部)std 函数实现将继续存在 if 触及函数对象状态的最后一个操作会破坏 std 函数,但您的代码仍会被视为存在 UB,因为它位于已破坏的 std 对象的方法中。