Qt 与 RAII 设计模式不兼容吗?

问题描述 投票:0回答: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);

上面的例子可以在这里找到。

QTimer
构造函数传递
this
指针,该指针成为
timer
的父级。当
*this
的析构函数被调用时,Qt 似乎会设置
QTimer
来析构
*this
。实际上,无需调用
delete timer

  1. 我是否可以调用
    delete timer;
    ,例如在
    unique_ptr
    的析构函数中?这会调用析构函数两次吗?
  2. 如果
    timer
    分配在堆栈上怎么办?
    *this
    知道吗?
c++ qt destructor smart-pointers raii
1个回答
0
投票

我可以调用删除计时器吗

如果您显式调用

delete timer
,QTimer 的析构函数(准确地说,QTimer 的 QObject 基类的析构函数)将从其父对象的子对象列表中删除 QTimer,以便稍后当父对象时调用对象自己的析构函数时,QTimer 不会被第二次删除。所以没关系。

例如在 unique_ptr 的析构函数中

使用

unique_ptr
(或
shared_ptr
),OTOH,你会遇到一个问题——虽然 QObject 类足够聪明,可以在销毁时更新其父 QObject,但它们知道如何更新
unique_ptr
shared_ptr
指向它们。因此,如果您分配一个
unique_ptr
shared_ptr
来指向您的 QTimer 对象,并且还为 QTimer 对象提供一个非 NULL 父对象(如您的示例中所示),那么您可能 will 会遇到双删除问题:一次是当 Qt 机制删除 QTimer 时,第二次是当
unique_ptr
尝试删除它包含的(现在悬空的)指针时。

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

unique_ptr
来跟踪它。

如果定时器分配在堆栈上怎么办? *这知道吗?

不,

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

© www.soinside.com 2019 - 2024. All rights reserved.