2010-09-17 24 views
5

Chúng tôi có nên xóa trước hoặc sau erase. Sự hiểu biết của tôi là cả hai đều ổn. Nó có đúng không?Chúng ta có nên xóa trước hoặc sau khi xóa cho một con trỏ trong vectơ không?

Ngoài ra, có trường hợp nào chúng tôi không muốn xóa phần tử trong khi xóa nó không? Tôi tin rằng phải có, nếu không, các erase sẽ được hạnh phúc để chịu trách nhiệm.

std::vector<foo*> bar; 
... 
for (vector<foo*>::iterator itr = bar.begin(); itr != bar.end(); itr++) 
{ 
    delete (*itr); //before OR 
    bar.erase(itr); 
    delete (*itr); //after??? 
} 
+0

bạn có nghĩa là 'std :: vector ' – sellibitze

+0

cảm ơn. sửa chữa. – pierrotlefou

+0

Tôi tin rằng bạn cũng có 'iter ++', nếu không vòng lặp sẽ không chấm dứt. – Naveen

Trả lời

10

"itr" phải được sử dụng như thế này;

for (vector<foo*>::iterator itr = bar.begin(); itr != bar.end();) 
{ 
    delete (*itr); 
    itr = bar.erase(itr); 
} 

Tuy nhiên, trước hết tôi muốn xóa tất cả các phần tử, sau đó xóa véc tơ;

for (vector<foo*>::iterator itr = bar.begin(); itr != bar.end(); ++itr) 
    delete (*itr); 
bar.clear(); 
+1

+1, tôi cũng sẽ chọn phiên bản thứ hai: theo cách này tôi sẽ không có tất cả những thay đổi của các phần tử trong vectơ. Ít nhất nếu sử dụng một vòng lặp với xóa, lặp đi lặp lại sẽ là phù hợp hơn. –

+0

Tôi đồng ý, nhưng, tôi không chắc chắn nếu vector :: xóa là tương thích với một reverse_iterator (để mệt mỏi để nghĩ rằng nó thông qua) –

+0

Bạn nên sử dụng các giải pháp ưa thích. Nó là ** O (n) ** trái ngược với ** O (n^2) **. – kevlar

4

Sử dụng trình lặp để xóa phần tử làm mất hiệu lực trình lặp. Bạn nên xóa mục trước khi nó bị xóa.

Bạn cũng nên sử dụng giá trị trả về từ xóa cho vòng lặp tiếp theo của bạn.

+0

nhận xét tốt nói chung nhưng bạn có thể cho chúng tôi biết lý do đằng sau "Bạn nên xóa mục trước khi xóa". Tôi không hiểu tại sao điều này lại xảy ra. Trong thực tế, tôi sẽ nghĩ rằng ngược lại sẽ an toàn hơn (ví dụ trong mã đa luồng). Hạn chế là bạn phải giữ giá trị của con trỏ trong một tạm thời trước khi gọi xóa hoặc bạn sẽ không thể xóa nó. Tôi không thấy nó cung cấp một lợi thế lớn vì vậy sẽ không khuyên bạn nên nó nhưng cách bạn worded câu trả lời của bạn có vẻ như xóa trước là cách duy nhất. – n1ckp

+0

@ n1ck: Anh ta hỏi giữa hai biến thể (tức là trước hoặc sau). Tôi chỉ đơn giản là giải quyết các câu hỏi. Tất nhiên bạn có thể di chuyển con trỏ đến một tạm thời, nhưng xóa chúng tại chỗ cũng hoạt động tốt cho hầu hết các ứng dụng. – Paul

+0

Harvey: chắc chắn, tôi chỉ nói rằng từ ngữ của bạn có lẽ không phải là tốt nhất vì nó có vẻ ngụ ý nó là cách duy nhất. Tôi nghĩ người đọc sẽ có thể hiểu nhưng tôi chỉ muốn hoàn toàn rõ ràng đó là tất cả. – n1ckp

1

Thực hiện erase sẽ làm mất hiệu lực trình lặp số vector. Vì vậy, *iter sẽ gọi hành vi không xác định. Do đó bạn cần thực hiện delete sau erase. Ngoài ra, bạn không thể erase các yếu tố từ một vector trong khi lặp qua nó (vì cùng một lý do, iter trở nên không hợp lệ để iter++ không hợp lệ). Trong trường hợp này, bạn có thể xóa cuộc gọi erase từ bên trong vòng lặp và thực hiện clear của vectơ ngoài vòng lặp.

2

Bản chất của vectơ xóa phần tử đầu tiên gây ra toàn bộ mảng dịch chuyển về phía trước, để giảm thử hoạt động này như sau:

std::vector<foo*> v1; 
//... 
while(!v1.empty()) 
{ 
    delete v1.back(); 
    v1.pop_back(); 
} 

Bằng cách này - phương pháp này không làm mất hiệu lực bất kỳ lặp (chỉ trên các mặt hàng đã xóa)

3

Ngoài ra, có trường hợp nào chúng tôi không muốn xóa phần tử trong khi xóa không?

Làm cách nào mà vectơ có thể biết được liệu có ai khác cần các đối tượng được trỏ tới không? Làm thế nào có thể nó thậm chí biết rằng các pointees được lưu trữ trên heap? Nó là hoàn toàn có thể có con trỏ đến các đối tượng tĩnh hoặc tự động trong vectơ, hoặc thậm chí con trỏ lơ lửng.

C++ 0x cho phép bạn thể hiện rằng vector nên sở hữu pointees:

std::vector<std::unique_ptr<foo>> vec; 

Bây giờ bạn không cần phải tự xóa bất cứ điều gì. Bằng cách xóa các con trỏ độc đáo, các điểm tương ứng của chúng cũng bị xóa. Container của con trỏ bản địa là rất hiếm trong C + + hiện đại.

Nếu bạn không có trình biên dịch C++ 0x, bạn có thể sử dụng std::vector<boost::shared_ptr<foo> > hoặc boost::ptr_vector<foo> để thay thế. Trình biên dịch hiện đại cung cấp shared_ptr trong không gian tên std::tr1 hoặc std nếu bạn #include <memory>.

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