我有使用std :: function模板实现回调的类。我最近注意到,我销毁了回调内的对象(即std :: function自行销毁)。
这是一个众所周知的问题吗? std :: function designer是否预见到它可能发生(std :: function对这种情况有弹性)?
示例代码:
E(g)$weight <- edge.betweenness(g)
答案 0 :(得分:3)
在非常复杂的系统中,这可能成为一个非常复杂的设计问题,主要依赖于信号和插槽类型的事件/通知设计。
如果将对象绑定函数/方法连接到信号并且对象被破坏,则没有固有的内置方法来防止第二次调用信号并访问被破坏的信号如果在对象被销毁时忘记断开插槽,则通过悬空指针对象。
缓解此问题的一种方法是将shared_ptrs绑定到对象而不是指针。但是,这可以为逻辑资源泄漏交换悬空指针,这可能不仅会泄漏内存,还会通过防止对象在应该被破坏时触发不可预测的行为。它还要求您将所有这些对象放在堆上。
绑定对象的弱引用可以解决这个问题而不会出现这些问题,但除非您找到适当的时间来清理所有已经被破坏的插槽,否则仍然会在信号中留下大量被破坏的插槽。它还在每次调用回调时强制执行运行时检查,以查看弱引用是否指向已经被销毁的对象,这可能会成为一个非平凡的开销,特别是因为弱引用有效性检查通常涉及将其转换为强大的参考和为线程安全做一些原子CAS类型的操作。您还必须将所有此类对象放在堆上。
另一种缓解此问题的方法是让您的信号设计返回一个强引用(shared_ptr
或有时unique_ptr
很好,例如)到一种代理对象,当被销毁时,会自动断开插槽与信号。然后连接到信号的客户端可以捕获这些对象,并以与其生命周期相关的方式将其存储在某个地方。
不幸的是,你不得不卷起袖子,为这些案件采用更高级别的设计。像std::function
这样的事情本身并不能防止这些安全问题。
另一种让你领略疼痛的头痛诱导剂是一个非常动态的系统,允许在不重新启动的情况下即时装载甚至卸载插件。在这些情况下,像std::function
这样的东西可能不仅仅指向已经被shared_ptr/weak_ptr
无法保护你的方式已被破坏的资源,而是它的功能。 s指向可能甚至不再在内存中,导致一种&#39;悬空函数指针&#39; 。正如在另一个答案中指出的那样,防范这些问题通常涉及额外的状态和处理,这些状态和处理对于许多常见情况可能是过度的。因此std::function
默认情况下不会阻止它们:如果需要,您必须在顶部构建这些安全结构。许多C ++标准库可用作高级构造的构建块,但不一定是自己的那个级别。
答案 1 :(得分:0)
正如Bjarne Stroustrup所说:“C让你很容易在脚下射击; C ++使得它变得更难,但当你这样做时,你的整条腿就会被打掉”。 Look here
你可以这样做:
class NotGonaMakeItToTheEnd
{
public:
NotGonaMakeItToTheEnd ( )
{
delete this;
}
};
编译器将允许这样做。
所有这些带有指针的东西都是用C ++进行C兼容性的,而不用付出你不用的东西成语。如果你真的想要制作一个整齐的指针柜而不是垃圾堆,你应该使用shared_ptr, unique_ptr
。