2013-09-24 23 views
5

Khi tạo một GUI với C++ và Qt bạn có thể tạo một nhãn ví dụ như thế này:C++ - Tại sao tôi tạo các tiện ích này trên heap?

QLabel* label = new QLabel("Hey you!", centralWidgetParent); 

Điều này tạo ra các đối tượng trên heap và sẽ ở lại đó cho đến khi tôi hoặc xóa nó bằng tay hoặc cha mẹ bị phá hủy. Câu hỏi của tôi bây giờ là tại sao tôi cần một con trỏ cho điều đó? Tại sao không tạo nó trên ngăn xếp?

//Create a member variable of Class MainWindow 
QLabel label; 

//Set parent to show it and give a text so the user can see it 
    QWidget* centralWidget = new QWidget(this); //Needed to add widgets to the window 
    this->setCentralWidget(centralWidget); 
    label.setParent(centralWidget); 
    label.setText("Haha"); 

Điều này làm việc tốt, tôi có thể thấy nhãn và nó không biến mất.

Chúng tôi sử dụng con trỏ trong C++ để cho phép nội dung nào đó tồn tại lâu hơn để chúng tôi có thể sử dụng đối tượng trong các phạm vi khác nhau. Nhưng khi tôi tạo một biến thành viên, nó sẽ không ở lại cho đến khi đối tượng bị phá hủy?

Chỉnh sửa: Có thể tôi không làm rõ điều đó đủ. Đây là lớp MainWindow:

class MainWindow : public QMainWindow 
{ 
    Q_OBJECT 
    QLabel label; //First introduced here... 

public: 
    MainWindow(QWidget *parent = 0); 
    ~MainWindow(); 
}; 

//Constructor 
MainWindow::MainWindow(QWidget *parent) 
    : QMainWindow(parent) 
{ 
    QWidget* centralWidget = new QWidget(this); 
    this->setCentralWidget(centralWidget); 
    label.setParent(centralWidget); 
    label.setText("Haha"); 
} 

Trả lời

3

Vì đó là cách Qt được thiết kế. Tôi nhận ra đó không phải là một câu trả lời rất thỏa mãn, nhưng Qt đã được thiết kế đơn giản như là "vật dụng được tạo ra trên heap, và cha mẹ chịu trách nhiệm xóa con của họ".

Nhận ra rằng nguồn gốc của Qt cũ, lớn hơn những gì chúng tôi xem là "hiện đại C++".

+0

Hmm ... cũng có nghĩa là ít nhất là có ý nghĩa. Cảm ơn bạn. – Davlog

8

Nếu số label của bạn nằm ngoài phạm vi, hàm hủy (QLabel::~QLabel) sẽ được gọi. Từ số docs:

Phá hủy đối tượng, xóa tất cả các đối tượng con của nó.

Không cần phải tạo đối tượng trên heap - bạn có thể đặt đối tượng trên ngăn xếp, nhưng sau đó bạn cần phải chịu trách nhiệm về tuổi thọ của đối tượng (một trong những vấn đề có vấn đề nhất về phân bổ dữ liệu heap là câu hỏi "ai và khi nào nên xóa các đối tượng này?", và trong Qt nó được xử lý bởi hệ thống phân cấp - bất cứ khi nào bạn xóa tiện ích con, tất cả các tiện ích con sẽ bị xóa).

Tại sao chương trình của bạn hoạt động - Tôi không biết - nó có thể không hoạt động (label bị hủy ở cuối phạm vi). Một vấn đề khác là - làm thế nào bạn sẽ thay đổi văn bản của label (từ một số khe, ví dụ) nếu bạn không có một tham chiếu đến nó?

Chỉnh sửa Tôi vừa thấy rằng label của bạn là thành viên của MainWindow. Nó là hoàn toàn tốt đẹp để có một đối tượng hoàn chỉnh, và không phải là con trỏ đến các đối tượng như các thành viên của lớp học của bạn, vì nó sẽ không bị phá hủy trước khi MainWindow là. Xin lưu ý rằng nếu bạn tạo thể hiện của MainWindow của bạn như thế này:

MainWindow *w = new MainWindow(); 

label sẽ được tạo ra trên heap.

+0

Tôi có thể gọi nhãn (một số chức năng) ở bất cứ đâu tôi muốn. Đó là một thành viên của lớp MainWindow của tôi vì vậy tôi có thể sử dụng nó trong bất kỳ vị trí nào, công khai hoặc riêng tư. – Davlog

3

Phân bổ một tiện ích dưới dạng biến cục bộ thường không phải là ý tưởng hay, vì thường thì nó sẽ nằm ngoài phạm vi trước khi hữu ích theo bất kỳ cách nào; kể từ QObject hỗ trợ mẫu thành phần thông qua các mối quan hệ "cha-con" (được tích hợp tốt với các trình phá hủy C++), thường là điều đơn giản nhất là chỉ khai thác tính năng như vậy.

Mặt khác, bạn có thể làm cho nó một thành viên của lớp MainWindow của bạn, hoặc nói chung phân bổ nó trong bất kỳ cách nào như vậy mà nó có một đời ít hơn tuổi thọ của mẹ. Trong thực tế, khi QLabel bị phá hủy, nó sẽ tự động xóa đăng ký từ cha mẹ của nó, tránh deallocation kép. Nhưng thường thoải mái hơn khi phân bổ các widget trên heap, đăng ký chúng như là con của cửa sổ hiện tại, vì thường bạn không cần truy cập nhiều widget sau khi tạo chúng (ví dụ như nhãn), vì vậy không cần thiết phải lộn xộn lớp học của bạn với các thành viên dữ liệu vô dụng. Bạn chỉ cần làm new QLabel(this, ...) vào công cụ xây dựng cửa sổ của bạn và đó là nó.

Những gì bạn nên không làm, thay vào đó, là để phân bổ các widget của bạn mà không new nếu cuộc đời của họ trở nên dài hơn tuổi thọ của cha mẹ của họ (ví dụ như đặt chúng trong một biến toàn cầu hoặc tĩnh) - làm điều này sẽ làm cho cha mẹ để cố gắng để delete họ về hủy diệt của nó, mà sẽ gây ra một vụ tai nạn ở tốt nhất, tham nhũng bộ nhớ im lặng lúc tồi tệ nhất. Điều này có thể được cố định (bằng cách hủy đăng ký thủ công các tiện ích trong trình phá hủy lớp học của bạn), nhưng tôi không thể tưởng tượng bất kỳ kịch bản nào mà một thứ như vậy sẽ hữu ích.

1

Lý do chính - khả năng tạo/xóa tiện ích động. QObject (và QWidget) desing là các lớp không thể có hàm tạo bản sao, vì vậy bạn không thể vượt qua là trong các đối số (theo giá trị/tham chiếu). Vì vậy, việc sử dụng con trỏ trong mọi trường hợp làm cho mã đơn giản và rõ ràng hơn.

4

Một điều cần nhớ là Qt sử dụng mô hình pimpl được gọi là nơi dữ liệu đối tượng được chia sẻ hoàn toàn và được quản lý phía sau lớp bạn thực sự khởi tạo. Xem tại đây: http://qt-project.org/wiki/Dpointer

Điểm mấu chốt là nếu bạn đang phân bổ trên ngăn xếp để tránh sử dụng đống, Qt chỉ cần kéo nhanh vào bạn và sử dụng heap.

Các vấn đề liên quan