gpt4 book ai didi

c++ - 调用期间自毁 std::function

转载 作者:行者123 更新时间:2023-11-30 02:39:07 27 4
gpt4 key购买 nike

我有使用 std::function 模板实现回调的类。我最近注意到,我销毁了回调中的对象(即 std::function 销毁了自身)。

这是一个众所周知的问题吗? std::function 设计者是否预见到它可能发生(std::function 是否对这种情况具有弹性)?

示例代码:

struct Sample
{
std::function<void()> callback;

void emit_callback ()
{
callback ();
}
}

void callback(Sample* object)
{
delete object;
}

/////////////////////////////////////////////

Sample* object = new Sample();
object->callback = std::bind(&callback, object);
object->emit_callback ();

最佳答案

在严重依赖信号和槽类型的事件/通知设计的非常复杂的系统中,这可能会成为一个相当大的设计问题。

如果您将一个对象绑定(bind)函数/方法连接到一个信号并且该对象被销毁,则没有任何固有的内置方法来防止信号被第二次调用并通过悬挂对象访问被销毁的对象如果您在对象被销毁时忘记断开插槽的连接,则指针。

缓解此问题的一种方法是将 shared_ptr 绑定(bind)到对象而不是指针。但是,这可以将悬空指针换成逻辑资源泄漏,这不仅会泄漏内存,还会通过阻止对象在应销毁时被销毁来触发不可预知的行为。它还要求您将所有此类对象放在堆上。

将弱引用绑定(bind)到对象可以解决此问题而不会出现这些问题,但仍然会在信号中留下大量被破坏的插槽,除非您找到合适的时间清理所有已被破坏的插槽。它还会在每次调用回调时强制执行运行时检查,以查看弱引用是否指向一个已经被销毁的对象,这可能会成为一个不小的开销,特别是因为弱引用有效性检查通常涉及将其转换为强引用并为线程安全做一些原子 CAS 类型的操作。您还必须将所有此类对象放在堆上。

另一种缓解这种情况的方法是让您的信号设计返回一个强引用(shared_ptr 或有时 unique_ptr 很好,例如)到一种代理对象,当销毁时,它会自动断开插槽与信号的连接。然后,连接到该信号的客户端可以捕获这些对象并将其以与其生命周期相关的方式存储在某个地方。

不幸的是,您确实需要卷起袖子为这些案例选择更高级别的设计。 std::function 之类的东西本身并不能防止这些安全问题。

另一个让您体验痛苦的令人头疼的东西是在一个非常动态的系统中,它允许在不重新启动的情况下动态加载甚至卸载插件。在那些情况下,std::function 之类的东西可能不仅会绑定(bind)到指向已经以连 shared_ptr/weak_ptr 也无法保护的方式被破坏的资源你,但它指向的函数甚至可能不再存在于内存中,导致一种“悬空函数指针”。正如在另一个答案中指出的那样,防止这些问题通常涉及额外的状态和处理,这些状态和处理对于许多常见场景来说可能是过大的。所以 std::function 默认情况下不会阻止它们:如果需要,您必须在顶部构建这些安全构造。许多 C++ 标准库可用作更高级别构造的构建 block ,但它们本身不一定处于该级别。

关于c++ - 调用期间自毁 std::function,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30155850/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com