2013-06-03 34 views
28

Tôi thấy nó được tham chiếu rất nhiều nhưng không có câu trả lời rõ ràng về chính xác nó là gì. Kinh nghiệm của tôi là với các ngôn ngữ cấp cao hơn, vì vậy tôi không quen thuộc về sự hiện diện của tính không hợp lệ trong một khuôn khổ bộ sưu tập.Hiệu lực của trình vòng lặp là gì?

Hiệu lực của trình vòng lặp là gì?

Tại sao lại xuất hiện? Tại sao khó giải quyết?

+2

Ngoài ra [Quy tắc không hợp lệ Iterator] (http://stackoverflow.com/questions/6438086/iterator-invalidation-rules) – mwerschy

+0

Tôi có thể cần giải thích tốt hơn về điều này, tôi không nghĩ rằng nó có liên quan gì đến các ngôn ngữ cấp cao/thấp. Tôi biết bạn không thể sửa đổi danh sách trong khi lặp lại trong 'C#'. –

+4

Bỏ phiếu để mở lại ... "những gì là" là một câu hỏi khác nhau mà không phải là ở tất cả các trả lời trong chuỗi liên kết. – djechlin

Trả lời

34
  1. Iterator là con trỏ được tôn vinh. Iterator vô hiệu hóa là rất nhiều như con trỏ vô hiệu; nó có nghĩa là nó đột nhiên trỏ đến dữ liệu rác.

  2. Bởi vì nó rất tự nhiên nhưng sai lầm khi làm những việc như thế này:

    for(iterator it = map.begin(); it != map.end(); ++it) { 
        map.erase(it->first); 
        // whoops, now map has been restructured and iterator 
        // still thinks itself is healthy 
    } 
    
  3. Bởi vì lỗi mà đúng không? Không có lỗi trình biên dịch, không cảnh báo, bạn bị mất. Bạn chỉ cần được đào tạo đủ tốt để theo dõi và ngăn chặn chúng. Lỗi rất ngấm ngầm nếu bạn không biết mình đang làm gì. Một trong những triết lý thiết kế của C++ là tốc độ an toàn. Kiểm tra thời gian chạy có thể dẫn đến việc vô hiệu hóa vòng lặp tới một ngoại lệ thay vì hành vi không xác định là quá đắt, theo quan điểm của các nhà thiết kế ngôn ngữ C++.

Bạn nên tình trạng báo động cao khi bạn đang iterating trên một cấu trúc dữ liệu và sửa đổi cấu trúc riêng của mình, thay vì chỉ đơn thuần là các đối tượng tổ chức trong đó. Tại thời điểm đó bạn có lẽ nên chạy đến tài liệu và kiểm tra xem các hoạt động là bất hợp pháp.

+8

Đây là lý do tại sao tôi thích thực tế là Visual Studio đã gỡ lỗi xây dựng. Theo mặc định, các thùng chứa C++ chuẩn sẽ kiểm tra xem chúng có hợp lệ trong các bản dựng gỡ lỗi hay không, giúp tìm ra các lỗi này. –

+0

@MooingDuck bạn không nên dựa vào hành vi đó, mặc dù. Nếu bạn trở nên quá gắn bó với các tính năng trình biên dịch tuyệt vời, khi bạn chuyển sang một nền tảng khác (có thể xảy ra một thời gian trong tương lai), bạn sẽ bị đốt cháy, cứng và nhanh chóng. –

+5

@ RichardJ.RossIII: Tùy thuộc vào? Rõ ràng không. Nhưng nó là tốt đẹp để có thêm một lớp bảo vệ cho khi tôi vít lên. –

6

Iterator huỷ bỏ hiệu lực là những gì sẽ xảy ra khi một loại iterator (một đối tượng hỗ trợ các nhà khai thác ++, và *) không đại diện cho một cách chính xác tình trạng của đối tượng đó được lặp. Ví dụ:

int *my_array = new int[15]; 
int *my_iterator = &my_array[2]; 

delete[] my_array; 

std::for_each(my_iterator, my_iterator + 5, ...); // invalid 

Điều đó dẫn đến hành vi không xác định do bộ nhớ được trỏ tới đã được hệ điều hành xác nhận lại.

Tuy nhiên, đây chỉ là một kịch bản và nhiều thứ khác khiến trình biến đổi bị 'vô hiệu' và bạn phải cẩn thận kiểm tra tài liệu của các đối tượng bạn đang sử dụng.

4

Sự cố xảy ra khi vùng chứa đang được xử lý bằng cách sử dụng trình lặp có hình dạng của nó đã thay đổi trong suốt quá trình. (Chúng tôi sẽ giả định một ứng dụng đơn luồng; đồng thời truy cập vào một thùng chứa có thể thay đổi được là toàn bộ 'sâu có thể sâu mà chúng tôi sẽ không xâm nhập vào trang này). Bằng cách "có sự thay đổi hình dạng của nó", một trong các loại sau đây của các đột biến có nghĩa là:

  • Một chèn vào container (tại bất kỳ địa điểm)
  • xóa của một phần tử từ container
  • Bất kỳ hoạt động thay đổi khóa (trong một số AssociativeContainer)
  • Bất kỳ thao tác nào thay đổi thứ tự của các thành phần trong vùng chứa được sắp xếp.
  • Bất kỳ thao tác phức tạp nào khác bao gồm một hoặc nhiều thao tác trên (chẳng hạn như tách một vùng chứa thành hai).

(Từ: http://c2.com/cgi/wiki?IteratorInvalidationProblem)

Khái niệm này là thực sự khá đơn giản, nhưng các tác dụng phụ có thể khá khó chịu. Tôi sẽ thêm rằng vấn đề này không chỉ ảnh hưởng đến C/C++ mà còn ảnh hưởng đến các ngôn ngữ cấp thấp hoặc trung cấp khác. (Trong một số trường hợp, ngay cả khi chúng không cho phép phân bổ đống trực tiếp)

+0

Không thể thay đổi khóa trong bất kỳ vùng chứa liên kết nào mà tôi biết. –

+0

@MooingHãy thực sự phụ thuộc vào những gì bạn xem là 'thay đổi quan trọng'. Tôi có thể xóa giá trị cho một khóa và thêm giá trị đó cho một khóa khác, không phải là 'thay đổi chính'? Chỉ vì các thùng chứa không tự nhiên hỗ trợ một cái gì đó, không có nghĩa là nó không thể được thực hiện. –

+0

@ RichardJ.RossIII: Tôi tin rằng bài đăng/liên kết đang đề cập đến sửa đổi thực tế của _key chính_, không phải là giá trị được liên kết với khóa đã nói. Việc sửa đổi dữ liệu liên quan yêu cầu vô hiệu hóa vòng lặp trong hầu hết các trường hợp. Việc sửa đổi _key chính nó sẽ yêu cầu xóa/tái định lý (lý thuyết). –

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