Qt信号:将动态分配的参数的所有权传递给一个插槽?

时间:2013-01-15 21:13:52

标签: c++ qt lifecycle signals-slots

我不知道如何准确地标题这个问题,所以这里是解释:

我有一个自定义小部件,在完成编辑后会发出一个信号,其中包含一个根据用户输入构建的自定义对象,例如

void GGActionEditor::finishEditing() {
  GGAction act;
  // Set up according to user input
  emit actionChanged(act);
}

在此代码中,连接到singal的接收器可以存储该对象的副本或以任何方式处理它,并且小部件可以忘记它。

但是当小部件可以从类层次构建不同类型的对象时,如何处理这种情况?像:

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个接收器接管参数。这可能适用于我的应用程序,但我对此感到不满
  2. 使用共享指针
    正如尤金在回答中所说,shared_ptr(或QSharedPointer)会简化这一过程。任何接收方和发送方都会使用共享指针,因此会自动管理生命周期。但是这会强制我的域模型也为包含这样一个Action对象的每个类使用共享指针。这不适合我的模型,因为这些类应该聚合动作。共享指针不适合保持对“属于”对象的对象的引用...
  3. 添加指示超车的参数
    在信号中添加bool*,表示某个接收器是否已接管该动作。如果值为真,接收器知道它不能再超过它。如果没有接收者接收它,发送者也知道它是否应该删除该对象。但接收器将以先到先得的方式接受该对象,这是相当随机的。并且它对界面进行了调查......
  4. 为不同的具体类别使用不同的信号
    在这种情况下,接收者的插槽可以知道使用哪个具体子类并制作该对象的副本。但是这为使用类层次结构可以很好地完成的事情添加了额外的信号/插槽...还必须为每个子类提供copy-c'tor。
  5. 向班级添加clone方法:
    与上面类似,但只有1个信号。多态clone将创建具体子类的副本。
  6. 使用专门的界面而不是信号/插槽
    创建一个GGIActionReceiver类,并在GGActionEditor中分配最多1个实例。此实例是唯一可以接管Action对象的可合并对象。其他人仍然可以发出信号,但他们不能超过指针。这样,发件人也知道是否必须删除该对象(没有接收者设置)

1 个答案:

答案 0 :(得分:0)

此处的一个选项是通过std :: shared_ptr<>使用共享所有权或其他一些参考计数机制。这样,只要有人需要,对象就会存在。

Qt的正常所有权模式并不常用,因为您无法确定有多少信号用户希望获得同一对象的所有权。

根据您的逻辑,共享所有权可能会导致闭环并打破那些您可能被迫在一两个抽象中出现漏洞。

确保不要将Qt所有权与shared_ptr混合 - 您的QObject必须没有父母。