2010-07-15 43 views
7

Tôi cần chèn con trỏ của các lớp (được kế thừa từ QObject) vào một Danh sách phát. Tôi biết rằng cú pháp sau đây có thể được sử dụng:Thêm con trỏ vào QList

.h

QList<MyObject*> list; 

cpp

list.append(new MyObject("first", 1)); 
list.append(new MyObject("second", 2)); 
... 

và sau đó giải phóng bộ nhớ:

if(!list.isEmpty()) 
{ 
    qDeleteAll(list); 
    list.clear(); 
} 

này nên có hiệu lực và không không gây ra bất kỳ rò rỉ bộ nhớ nào (theo như tôi biết). Tuy nhiên, tôi cần phải khởi tạo các đối tượng trước khi thêm chúng vào bộ sưu tập. Đoạn mã sau có thể gây ra một số lỗi như rò rỉ bộ nhớ hoặc con trỏ lơ lửng (tôi sẽ sử dụng cùng một cách để xóa con trỏ như trên)?

MyObject *obj; 

for(i = 0; i < 5; i++) 
{ 
    obj = new MyObject(); 
    if(!obj.Init(i, map.values(i))) 
    { 
     // handle error 
    } 
    else 
    { 
     list.append(obj); 
    } 
} 

Cảm ơn.

+1

chỉ là một lưu ý: if (list.isEmpty()) khi sử dụng qDeleteAll() là thừa, tôi chỉ bỏ qua nó. –

Trả lời

4

nếu bạn chăm sóc "obj" (trường hợp phân bổ nhưng không được khởi tạo) trong "// xử lý lỗi" trường hợp, mã của bạn là ok.

0

Sử dụng RAII (Phân bổ tài nguyên là khởi tạo). Khởi tạo trực tiếp đối tượng trong hàm tạo.

Sau đó, mã sẽ trông như thế:

for(i = 0; i < 5; i++) 
{ 
    list.append(new MyObject(i, map.values(i))); 
    // In case of initialization failure, throw exception from the constructor 
} 
+2

nếu ngoại lệ không được phép trong môi trường của anh thì sao? – akira

+0

... thì cần phải tìm một cơ chế khác để báo cáo lỗi. Nó có thể giống như một hàm "getLastError" (có thể là luồng an toàn). Nhưng tại sao giả định ngoại lệ không được phép? Không có gì được đề cập trong câu hỏi, vì vậy tôi giữ nó đơn giản. –

+0

Ném một ngoại lệ là trong thực tế theo xem xét của tôi. Trong trường hợp thất bại khởi tạo, tôi muốn nhận một thông báo lỗi từ đối tượng cho các mục đích gỡ lỗi (hiện đang sử dụng phương thức public obj.getError()). Tôi biết rằng có thể báo cáo lỗi với các ngoại lệ (ví dụ: ném một chuỗi), nhưng hiện tại tôi đang chơi với các giá trị trả lại và thông báo lỗi (như thư viện Qt) và tôi muốn ở lại trên đường dẫn đó. Đó là lý do chính tại sao tôi hỏi nếu mã thứ hai là tốt. – Routa

0

Bạn có thể sử dụng QScopedPointer ..

Từ 4.6 tài liệu Qt,

Các cửa hàng lớp QScopedPointer một con trỏ đến một đối tượng được cấp phát động, và xóa nó khi tiêu hủy. Quản lý các đối tượng được phân bổ heap theo cách thủ công là khó khăn và dễ bị lỗi, với kết quả chung là mã rò rỉ bộ nhớ và khó duy trì. QScopedPointer là một lớp tiện ích nhỏ giúp đơn giản hoá điều này bằng cách gán quyền sở hữu bộ nhớ dựa trên stack cho phân bổ đống, thường được gọi là việc mua lại tài nguyên là khởi tạo (RAII).

Hy vọng nó giúp ..

Edit:

Ví dụ,

Bạn sẽ sử dụng,

QScopedPointer<QWidget> p(new QWidget()); 

thay vì

QWidget *p = new QWidget(); 

và thêm QScopedPointer vào QList mà không phải lo lắng về việc bị rò rỉ bộ nhớ rò rỉ bộ nhớ.

+0

để vòng lặp bên trong trông như thế này: QScopedPointer obj (new MyObject()); if (obj-> Init (map.values ​​(i)) {list.append (obj.take());} ... thêm vào đó để trả lời để xem lợi thế. – akira

+0

xin lỗi tôi không thể hiểu ví dụ ur. chỉ cần thêm một ví dụ cơ bản từ các tài liệu để làm cho mọi thứ rõ ràng .. Tôi dint thêm điều này trước với hy vọng rằng mọi người sẽ tìm thấy nó từ các tài liệu .. :) – liaK

+0

phần nào trong ví dụ 3 dòng cơ bản của tôi không rõ ràng? btw, ví dụ của bạn sẽ dẫn đến một segfault, bởi vì ptr scoped vẫn OWNS dụ, đó là lý do tại sao tôi sử dụng .take(). – akira

3

Sử dụng QSharedPointer thay thế.

QList<QSharedPointer<MyObject> > list; 

Để bộ nhớ miễn phí, bạn chỉ phải làm

if(!list.isEmpty()) 
{ 
    list.clear(); 
} 

Để thêm vào danh sách

list.append(QSharedPointer<MyObject>(new MyObject("first", 1))); 
list.append(QSharedPointer<MyObject>(new MyObject("second", 2))); 
Các vấn đề liên quan