2008-11-11 18 views
7

Nếu tôi có mã sau,MyVector.erase (myPtr) có xóa đối tượng được chỉ bởi myPtr không?

Foo *f = new Foo(); 
vector<Foo*> vect; 
vect.push_back(f); 
// do stuff 
vect.erase(f); 

Tôi đã tạo rò rỉ bộ nhớ? Tôi đoán vậy, nhưng từ xóa cho cảm giác rằng nó đang xóa nó.

Viết này, tôi tự hỏi nếu nó không phải là một sai lầm để đặt một con trỏ trong một vector STL. Bạn nghĩ sao?

Trả lời

8

Có, bạn đã tạo rò rỉ bộ nhớ theo đó. std :: vector và các thùng chứa khác sẽ chỉ loại bỏ con trỏ, chúng sẽ không giải phóng bộ nhớ mà con trỏ trỏ tới.

Không có gì lạ khi đặt con trỏ vào vùng chứa thư viện chuẩn. Tuy nhiên, vấn đề là bạn phải theo dõi việc xóa nó khi xóa nó khỏi vùng chứa. Một tốt hơn, nhưng đơn giản, cách để làm điều trên, là sử dụng tăng :: shared_ptr:

{ 
    boost::shared_ptr<foo> f(new foo); 

    std::vector< boost::shared_ptr<foo> > v; 
    v.push_back(f); 
    v.erase(v.begin()); 
} /* if the last copy of foo goes out of scope, the memory is automatically freed */ 

Các tiêu chuẩn tiếp theo C++ (gọi tắt là C++ 1x và C++ 0x thường) sẽ bao gồm std::shared_ptr. Ở đó, bạn cũng sẽ có thể sử dụng std::unique_ptr<T> nhanh hơn, vì nó không cho phép sao chép. Sử dụng std::unique_ptr với các vùng chứa trong C++ 0x tương tự như thư viện ptr_container.

+0

Hãy cẩn thận khi sử dụng tăng :: shared_ptr, vì câu trả lời này chỉ thị thay vì auto_ptr. STL container không thể được sử dụng ở tất cả với auto_ptr (lý do là một chút dài để giải thích trong bình luận này). – Gorpik

+0

Ok, tôi lưu ý điều này. Cảm ơn ! – Barth

1

Nó chắc chắn không phải là một sai lầm để trỏ một con trỏ vào một container tiêu chuẩn (đó là một sai lầm để làm cho một container của auto_ptr tuy nhiên). Có, bạn cần xóa một cách rõ ràng để giải phóng bộ nhớ được chỉ bởi các yếu tố riêng lẻ hoặc bạn có thể sử dụng một trong các tăng smart pointers.

4

Một tùy chọn khác là sử dụng Boost Pointer Containers. Chúng được thiết kế để làm chính xác những gì bạn muốn.

2

Ngoài ra còn có tăng :: ptr_vector container.

Nó biết rằng nó đang giữ con trỏ mà nó sở hữu và do đó tự động xóa chúng.

Là một mặt tốt đẹp có ảnh hưởng, khi truy cập các phần tử, nó trả về một tham chiếu đến đối tượng không phải là con trỏ để làm cho mã trông đẹp.

Foo *f = new Foo(); 
boost::ptr_vector<Foo> vect; 
vect.push_back(f); 
// do stuff 
vect.erase(f); 
+0

Tham khảo tuyệt vời, cảm ơn vì điều đó. Nó chỉ xảy ra như vậy mà tôi dành vài ngày qua để cấu trúc lại các cấu trúc dữ liệu của thùng chứa, tăng :: gián tiếp_iterator đã hữu ích nhưng các thùng chứa ptr_xxx này thậm chí còn tốt hơn tôi nghĩ ... Có lẽ tôi sẽ cần tái cấu trúc lại;) – Roel

1

vectơ xóa dữ liệu chứa trong đó. Vì vectơ của bạn chứa con trỏ, nó chỉ xóa con trỏ, chứ không xóa dữ liệu mà chúng có thể hoặc không trỏ tới.

Đó là một quy tắc khá chung trong C++ rằng bộ nhớ được phát hành ở nơi được cấp phát. Vectơ không phân bổ bất cứ điều gì con trỏ trỏ đến, vì vậy nó không được giải phóng nó.

Có thể bạn không nên lưu trữ con trỏ trong vectơ của mình ngay từ đầu. Trong nhiều trường hợp, bạn sẽ được tốt hơn off với một cái gì đó như thế này:

vector<Foo> vect; 
vect.push_back(Foo()); 
// do stuff 
vect.erase(f); 

Tất nhiên điều này giả định rằng Foo là copyable, và đó copy constructor của nó không phải là quá đắt, nhưng nó tránh rò rỉ bộ nhớ, và bạn don không phải nhớ để xóa đối tượng Foo. Một cách tiếp cận khác là sử dụng con trỏ thông minh (chẳng hạn như shared_ptr của Boost), nhưng bạn có thể không cần ngữ nghĩa của con trỏ, trong trường hợp đó, giải pháp đơn giản là giải pháp tốt nhất.

1

Vùng chứa STL sẽ không giải phóng bộ nhớ của bạn.Lời khuyên tốt nhất là sử dụng con trỏ thông minh, biết rằng std :: auto_ptr sẽ không vừa với các vùng chứa. Tôi sẽ khuyên bạn nên tăng :: shared_ptr, hoặc nếu nhà cung cấp trình biên dịch của bạn có hỗ trợ cho phần mở rộng TR1 (nhiều người làm), bạn có thể sử dụng std :: tr1 :: shared_ptr.

Cũng lưu ý rằng vectơ sẽ không giải phóng bộ nhớ trong dành riêng cho con trỏ. std :: vectơ không bao giờ giảm kích thước ngay cả khi có cuộc gọi đến rõ ràng(). Nếu bạn cần phải giảm kích thước một vector, bạn sẽ phải sử dụng để tạo một vector khác và trao đổi nội dung.

2

Để làm rõ lý do tại sao con trỏ không bị xóa, hãy xem xét

std::vector<char const*> strings; 
strings.push_back("hello"); 
strings.push_back("world"); 
// .erase should not call delete, pointers are to literals 

std::vector<int*> arrays; 
strings.push_back(new int[10]); 
strings.push_back(new int[20]); 
// .erase should call delete[] instead of delete 

std::vector<unsigned char*> raw; 
strings.push_back(malloc(1000)); 
strings.push_back(malloc(2000)); 
// .erase should call free() instead of delete 

Nói chung, vector<T*>::erase không thể đoán cách bạn muốn vứt bỏ một T*.

+0

Hãy xem xét những gì? Xin vui lòng cho chúng tôi biết những gì chúng ta nên xem xét, ngay cả khi chỉ một thời gian ngắn. Bạn dường như không xóa bất cứ điều gì cả, và không ai đẩy bạn chia sẻ bất kỳ tài liệu tham khảo. Sau khi nghĩ về nó trong vài phút, tôi nghĩ có lẽ ý định của bạn là để chúng tôi chú ý vấn đề với 'char const *' của bạn, nhưng tôi không chắc ý định của bạn là gì. Xin đừng để chúng tôi với một cái móc đá. -1 Nếu tôi đã đúng về ý định của bạn, chỉ cần thêm "Điều đó sẽ làm gì" và trường hợp như vậy "" sẽ hữu ích. – Aaron

+0

@Aaron: Hãy xem xét liệu nó có phù hợp với 'std :: vector :: xóa (lặp)' để gọi 'delete * iter', được đưa ra các ví dụ ở trên không. Và để đưa ra câu trả lời: Không. Ví dụ đầu tiên gọi 'delete' trên chuỗi ký tự (không nên làm gì cả), trong ví dụ thứ hai' erase' sẽ phải gọi 'delete []' và trong trường hợp thứ ba 'erase' sẽ cần gọi 'free()'. – MSalters

+0

Phải. Tôi có lẽ nên đã bắt gặp vấn đề với mẫu thứ hai (mảng); không chắc tại sao tôi không biết. Đối với một thứ ba (malloc): Tôi sẽ thừa nhận rằng nó đã được rất lâu kể từ khi tôi đã sử dụng malloc cho bất cứ điều gì mà tôi quên bạn không phải trộn lẫn mới/miễn phí hoặc malloc/xóa. Mẫu thứ ba đặc biệt là lý do tại sao bạn nên giải thích với ít nhất một hoặc hai dòng; vì những người như tôi. ;) Loại bỏ -1 và nếu bạn đưa nhận xét của mình vào câu trả lời, tôi sẽ tạo +1 đó. – Aaron

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