代码之家  ›  专栏  ›  技术社区  ›  Bobby

Qt是否与RAII设计模式不兼容?

  •  -1
  • Bobby  · 技术社区  · 1 年前

    良好编码实践的一个重要经验法则是

    每一个 new 必须由匹配 delete

    在中讨论 this 上一个问题。通常,我们将此规则封装在RAII类中,如 std::unique_ptr 然而,Qt似乎打破了这种模式。例如,要创建 QTimer ,用户可以执行以下操作:

    QTimer *timer = new QTimer(this);
    connect(timer, &QTimer::timeout, this, QOverload<>::of(&AnalogClock::update));
    timer->start(1000);
    

    可以找到上面的例子 here 这个 Q定时器 构造函数被传递 this 指针,它成为的父级 timer 。似乎Qt随后设置了 *this 销毁 Q定时器 当的析构函数 *这个 被调用。实际上,没有必要打电话 delete timer .

    1. 我可以打电话吗 delete timer; 无论如何,例如在的析构函数中 unique_ptr ?那会调用析构函数两次吗?
    2. 如果…怎么办 定时器 是在堆栈上分配的吗?做 *这个 知道吗?
    1 回复  |  直到 1 年前
        1
  •  1
  •   Jeremy Friesner    1 年前

    我可以调用删除计时器吗

    如果您明确调用 delete timer ,QTimer的析构函数(确切地说,是QTimer QObject基类的析构因子)将从其父对象的子列表中删除QTimer,这样以后当调用父对象自己的析构符时,QTimeer就不会被第二次删除。所以没关系。

    例如在unique_ptr的析构函数中

    具有 unique_ptr (或 shared_ptr ),OTOH,你会遇到一个问题——虽然QObject类足够聪明,可以在它们被破坏时更新它们的父QObject,但它们确实这样做了 知道如何更新 unique_ptr shared_ptr 这指向了他们。所以如果你分配一个 unique_ptr shared_ptr 指向您的QTimer对象,并为QTimer提供非NULL父对象(如您的示例中所示),那么您可能 存在双重删除问题:一次是当Qt机制删除QTimer时,第二次是当 unique_ptr 尝试删除它所包含的(现在悬空的)指针。(请注意,有一个 QPointer 类,其表现为指向QObject的弱指针,这可能很有用)。

    正因为如此,最好不要尝试混合使用Qt的对象树系统和C++智能指针。也就是说,如果你要给你的QTimer一个非NULL的父级,那么你应该依靠这个父级来处理QTimer的删除,而不是试图用 unique_ptr .

    如果在堆栈上分配了计时器怎么办?这个知道吗?

    this 的析构函数不知道对象在堆栈上,因此它将尝试删除它,从而导致未定义的行为。因此,如果要在堆栈上分配QTimer,则不应为其指定非NULL父指针。