Qt and pointers

Qt and pointers

本文关键字:pointers and Qt      更新时间:2023-10-16

我是Qt的新手,我正在阅读几个Qt项目以获得基本知识。在浏览不同的类时,似乎总是使用指向QWidget的指针。

示例:

class ExempleWidget : public QWidget
{
Q_OBJECT
public:
ExempleWidget();
~ExempleWidget();
private:
QPushButton * m_stopButton;
QPushButton * m_playButton;
QHBoxLayout * m_hBoxLayout;
QVBoxLayout * m_vBoxLayout;
};

是否有任何理由使用'QPushButton'*'QHBoxLayout'*等的指针?我们可以只使用值吗?这样我们就不必为"新">的"删除">

例如

private:
QPushButton m_stopButton;

编辑:

所有的答案似乎都指出了Qt类之间的层次结构。这对我来说是一个很好的理由,我毫不怀疑这一点,但假设我的类的小部件(*m_stopButton*和*m_playButton*)之间没有链接。

在这种情况下,我可以安全地将它们声明为值,不是吗?当类将被删除时,成员也将被删除,因此无论指针与否,我们都将有相同的行为。

如果希望完全控制对象的生存期,则需要使用指针。例如

  1. 如果您想在构造函数中的初始化列表处理完毕后的某个时刻构造类成员。

  2. 如果您想在编译器生成的析构函数结束语运行之前的某个时刻析构函数类成员。

当编译器为您构建和破坏对象实例时,不使用指针是完全安全的。

只要原始指针拥有它们所指向的资源,它们就会容易出错:忘记删除所拥有的资源、多次删除资源或取消引用已删除的资源都是错误的。

使用不拥有资源的原始指针(与智能指针相反)(当资源将由其他人释放时)可能仍然是过早优化的情况。使用原始指针容易将"小"代码更改转化为资源泄漏:

class X : public QObject {
QObject * a;
public:
// OK
X() : a(new QObject(this)) {}
// an error - we need to add a destructor that deletes a
X() : a(new QObject) {}
}
class X : public QObject P
QScopedPointer<QObject> a;
public:
// Both OK
X() : a(new QObject(this)) {}
X() : a(new QObject) {}
};

智能指针-C++11的std::unique_ptr,Qt 4.6的QScopedPointer-保证删除总是发生,并且对已删除资源的访问相当于空指针解引用,因此名义上由处理器硬件捕获并发出信号。

在C++中,类成员和自动变量的构造和销毁顺序是固定的。在下面的例子中,构造顺序是总是a然后是b,破坏顺序是总是b然后是a。这是非常重要的。

class C {
A a;
B b;
};
void test() {
A a;
B b;
}

因此,除非另有规定,否则以下代码至少在Qt3、Qt4和Qt5下是有效的并且行为正确。

class C : public QWidget {
QWidget a;
QLabel b;
public:
C(QWidget * parent = 0) : QWidget(parent), a(this), b(&a) {}
}
// Qt 4.6 & up only
class C : public QWidget {
QScopedPointer<QWidget> a;
QScopedPointer<QLabel> b;
public:
C(QWidget * parent = 0) : QWidget(parent), 
a(new QWidget(this)),
b(new QLabel(a.data())) {}
};
// C++11 only
class C : public QWidget {
std::unique_ptr<QWidget> a;
std::unique_ptr<QLabel> b;
public:
C(QWidget * parent = 0) : QWidget(parent), 
a(new QWidget(this)), 
b(new QLabel(a.data())) {}
};      
void test() {
QWidget c;
QWidget a(&c);
QLabel b(&a);
}

在所有情况下,施工顺序为:c, a, b;破坏顺序为:CCD_ 8。

Qt基本上设计为C++anno 1996左右(或者非常Java风格,如果你愿意的话)。很多指针,很多继承。

当然,他们经常使用指针的一个原因是继承几乎无处不在,它避免了任何与切片相关的问题。

另一个原因是Qt有一个强大的约定,即通过给每个对象一个父对象来处理内存管理,因此当父对象被销毁时,它会在其子对象上调用delete

如果您将对象声明为本地对象,而不是指向用new分配的对象的指针,那么您必须小心不要给它一个父对象,或者确保它在其父对象之前超出范围,以确保永远不会调用delete

因为在构造函数中你可以给它们一个父级,所以当删除父级时,它们也会自动删除。

根据项目的不同,也可能有其他原因(比如根据类逻辑创建和销毁方法)。

是有原因的。QObject的所有子类都可以使用parent属性放在层次结构中。它非常有用,因为它允许QObject上的操作传播到所有子层次结构。其中一个操作是小部件的showhide,另一个是对象销毁。

当你删除一个QObject(也就是Qwidget)时,他的所有孩子也会被删除。正如医生所说的

警告:所有子对象都将被删除。如果这些对象中的任何一个处于打开状态堆栈或全局,你的程序迟早会崩溃

此外,您还可以将对象移动到其他线程。为了做到这一点,您需要这些对象位于进程中所有线程都可用的内存区域中。堆栈用于单个线程,因此不合适。

从纯语言的角度来看 ,您只有构造函数

QObject::QObject( QObject * parent = 0 );

如果向父对象提供不同于NULL的值,则该值的生存期应大于正在构建的对象。否则,它可能使用无效的引用。

基本上,他们想要建立不同的机制,并且有不同的约束(包括向后兼容性),这是他们选择的机制。

原因是历史原因。在较旧的Qt版本中,当您将父小部件传递给成员小部件的构造函数时,父QWidget::~QWidget会调用子小部件上的delete

在当前的Qt版本中,添加了一个检查子窗口小部件是否已经被删除,这意味着你现在可以让它们成为普通成员。