我不知道如何准确地命名这个问题,所以这里是解释:
我有一个自定义小部件,它在完成编辑后使用从用户输入构建的自定义对象发出信号,例如
void GGActionEditor::finishEditing() {
GGAction act;
// Set up according to user input
emit actionChanged(act);
}
在这段代码中,连接到信号的接收器可以存储该对象的副本或以任何合适的方式处理它,而小部件可以忘记它。
但是当小部件可以从类层次结构中构建不同类型的对象时,如何处理这种情况呢?喜欢:
void GGActionEditor::finishEditing() {
GGAction *pAct;
// Create and set up according to user input, e.g.
if (...) pAct = new GGSpecialAction;
else pAct = new SimpleAction;
emit actionChanged(pAct);
}
处理对象生命周期这种情况的最佳解决方案是什么?小部件无法知道是否有任何接收者接管了 Action 对象。此外,如果连接了多个接收器,则它们都不知道是否有另一个对象接管了参数……
在“最佳”情况下,这可能会导致泄漏;但也可能导致参数被多次删除。
更新:
有关我的实际情况的更多信息,但是,我也对一般解决方案感兴趣:
传递的对象将由接收者存储并保存在应用程序的域模型中。该模型将负责稍后将其删除。
简单的解决方案是像上面描述的“简单”按值情况一样处理这种情况。但是,如果根本没有连接接收器,对象就会泄漏;并且不能 100% 保证只有 1 个接收器会这样做(在我的实际应用程序逻辑中,情况就是这样,但不能以这种方式检查或强制执行)。
我想出了一些可能的解决方案,并对任何评论或补充感兴趣:
- 只是希望它会成功:
假设将有 1 个接收器接管参数。这可能适用于我的应用程序,但我对此并不满意 - 使用共享指针:
正如 Eugene 在回答中所说,shared_ptr(或 QSharedPointer)会简化这一点。任何接收者和发送者都将使用共享指针,因此生命周期是自动管理的。但这迫使我的域模型也为每个拥有此类 Action 对象的类使用共享指针。这不适合我的模型,因为这些类应该聚合动作。共享指针不适合持有对“属于”对象的对象的引用...... - 添加指示超车的参数:在信号中
添加一个bool*
,指示是否某个接收器已经接管了该动作。如果该值为真,接收者就知道它不能再超越它了。如果没有接收者拿走它,发送者也知道它是否应该删除该对象。但是哪个接收者会以先到先得的方式接收对象是完全随机的。它污染了界面...... - 对不同的具体类使用不同的信号:
在这种情况下,接收者的槽可以知道使用了哪个具体子类并制作对象的副本。但这为使用类层次结构可以很好地完成的事情增加了额外的信号/插槽......此外,每个子类都必须有一个copy-c'tor。 - 向类添加
clone
方法:
与上面类似,但只有 1 个信号。多态clone
将创建具体子类的副本。 - 使用专用接口而不是信号/插槽:
创建一个GGIActionReceiver
类,并在GGActionEditor
. 此实例是接管 Action 对象的唯一合格对象。其他人仍然可以发出信号,但他们不能超过指针。这样,发送者也知道是否必须删除对象(没有设置接收者)