Qt和指针

Iri*_*ces 8 c++ qt pointers

我是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;
};
Run Code Online (Sandbox Code Playgroud)

是否有任何理由使用指针'QPushButton'*'QHBoxLayout'*等?我们可以只使用价值观,所以我们不必费心去'新''删除'?嗯,我知道我们可以,但这是一个很好的方法吗?

例如

private:
    QPushButton m_stopButton;
Run Code Online (Sandbox Code Playgroud)

编辑:

所有答案似乎都指出了Qt类之间的层次结构.这对我来说是一个足够好的理由,我不怀疑这一点,但是让我们说我班级的小部件之间没有联系(*m_stopButton*和*m_playButton*).

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

Rei*_*ica 6

当你希望完全控制对象的生命周期时,你想要使用指针.例如

  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) {}
};
Run Code Online (Sandbox Code Playgroud)

智能指针--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;
}
Run Code Online (Sandbox Code Playgroud)

因此,除非另有说明,否则以下代码有效并且在至少Qt 3,Qt 4和Qt 5下正确运行.

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);
}
Run Code Online (Sandbox Code Playgroud)

在所有情况下,施工顺序为:c, a, b; 销毁令是:b, a, c.


jal*_*alf 5

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

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

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

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


Jep*_*sen 3

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

还可能有其他原因,具体取决于项目(例如根据类逻辑创建和销毁方法)。

  • Qt 具有垃圾回收功能这一事实并不是使用动态分配对象的理由。因此,这**不是**答案。@MSalters (5认同)
  • @paulm“当在堆上创建 QObject 时(即使用 new 创建),可以按任何顺序从它们构造一棵树 [...] 当在堆栈上创建 QObject 时,应用相同的行为。” -- [Qt 文档](http://qt-project.org/doc/qt-4.8/objecttrees.html)。 (2认同)
  • @Jefffrey 您链接的文档显示了使用基于堆栈的 QObjects 的真正问题,解释自:“但现在考虑一下如果我们交换构造顺序会发生什么,如第二个片段所示”。对象声明的顺序现在很重要并且可能是一个问题。 (2认同)