簡體   English   中英

Qt和指針

[英]Qt and 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;
};

是否有任何理由使用指針'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) {}
};

智能指針QScopedPointer ++ 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;
}

因此,除非另有說明,否則以下代碼有效並且在至少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);
}

在所有情況下,施工順序為: c, a, b ; 銷毀順序是: b, a, c

Qt基本上設計為C ++ anno 1996左右(如果你願意的話,非常Java風格)。 很多指針,很多繼承。

當然,他們經常使用指針的一個原因是幾乎無處不在的繼承,它避免了任何與切片相關的問題。

另一個原因是Qt有一個強大的約定,即通過給每個對象一個父對象來處理內存管理,這樣當父對象被銷毀時,它會調用其子對象的delete

如果您將對象聲明為本地對象而不是指向使用new分配的內容的指針,那么您必須小心不要給它父級,或者確保它在其父級之前超出范圍以確保永遠不會delete調用。

因為在構造函數中,您可以為它們提供父級,因此當刪除父級時,它們會被自動刪除。

還有其他原因,具體取決於項目(如根據類邏輯創建和銷毀方法)。

是的,有一個原因。 可以使用parent屬性將QObject所有子類放在層次結構中。 它非常有用,因為它允許將QObject上的操作傳播到所有子層次結構。 其中一個操作是為小部件showhide ,另一個是對象銷毀。

刪除QObject (即Qwidget )時,他的所有孩子也會被刪除。 正如醫生說的那樣

警告:刪除所有子對象。 如果這些對象中的任何一個在堆棧或全局上,則程序遲早會崩潰

此外,您可以將對象移動到其他線程。 為此,您需要將這些對象放在可供進程中所有線程使用的內存區域中。 堆棧用於單個線程,因此不合適。

在純語言的角度來看 ,你只有構造函數

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

如果為不同於NULL父項提供值,則此值的生命周期應大於正在構造的對象。 否則它可能使用無效的引用。

基本上他們有不同的機制,他們想要采用不同的約束(包括向后兼容 ),這是他們選擇的機制。

原因是歷史性的。 在較舊的Qt版本中,當您將父窗口小部件傳遞給成員窗口小部件的構造函數時,父窗口小部件上的父QWidget::~QWidget調用delete

在當前的Qt版本中,添加了一個檢查以查看子窗口小部件是否已被刪除,這意味着您現在可以使它們成為普通成員。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM