2013-04-29 29 views
14

Nếu tôi đang sử dụng iterator trong vòng lặp for và tôi sử dụng erase trên lặp lại hiện tại của trình lặp, vòng lặp for sẽ tiếp tục tốt và truy cập phần còn lại của các yếu tố list?Xóa khi đang lặp một tiêu chuẩn: danh sách

Từ nội dung tôi đã đọc, trường hợp này phải là trường hợp và là đặc điểm phân biệt chính của list so với deque hoặc vector. Vì mục đích của tôi, một queue có thể hoạt động nhưng tôi cần hành vi này.

Đây là vòng lặp Tôi đang xem xét:

std::list<Sequence>::iterator iterator; 
    iterator=m_concurrents.begin(); 
    for (;iterator!=m_concurrents.end();++iterator){ 
     if (iterator->passes()){ 
      m_concurrents.erase(iterator); 
     } 
    } 

Trả lời

43

Cách thành ngữ để viết vòng lặp đó sẽ là:

for (auto i = list.begin(); i != list.end();) { 
    if (condition) 
     i = list.erase(i); 
    else 
     ++i; 
} 

Bạn có thể làm điều tương tự với một set, multiset, map, hoặc multimap. Đối với các thùng chứa này, bạn có thể xóa một phần tử mà không ảnh hưởng đến hiệu lực của bất kỳ trình lặp nào đến các phần tử khác. Các đồ chứa khác như vector hoặc deque không phải là loại tốt. Đối với những thùng chứa chỉ các yếu tố trước khi iterator bị xóa vẫn bị ảnh hưởng. Sự khác biệt này đơn giản chỉ vì các phần tử cửa hàng của list trong các nút được phân bổ riêng lẻ. Thật dễ dàng để lấy một liên kết. vector s là tiếp giáp, lấy một phần tử di chuyển tất cả các phần tử sau khi nó trở lại một vị trí.

Vòng lặp của bạn bị hỏng vì bạn xóa phần tử tại i trên một số điều kiện nhất định. i không còn là trình lặp hợp lệ sau cuộc gọi đó nữa. Vòng for của bạn sau đó tăng i, nhưng i không hợp lệ. Địa ngục trên trái đất xảy ra sau đó. Đây là tình huống chính xác đó là lý do tại sao erase trả về trình lặp cho phần tử sau khi phần tử đã bị xóa ... để bạn có thể tiếp tục đi qua list.

Bạn cũng có thể sử dụng list::remove_if:

list.remove_if([](auto& i) { return i > 10; }); 

Trong lambda, trả về true nếu nguyên tố này cần được loại bỏ. Trong ví dụ này, nó sẽ xóa tất cả các phần tử lớn hơn 10.

+0

trong ví dụ này, bạn đang dừng lặp lại khi nó đã bị xóa, do đó không lặp qua danh sách để xem xét các yếu tố khác. Tôi rất thú vị khi lặp lại toàn bộ danh sách và xóa các mục nhập như mong muốn. Từ những gì tôi hiểu, điều này là an toàn với một 'danh sách' nhưng không an toàn với các thùng chứa khác. Đó là trái tim của câu hỏi của tôi, xin lỗi nếu điều đó không rõ ràng. – johnbakers

+2

Điều này sẽ không hoạt động đối với các trình biên dịch không phải C++ 11. Các phương thức thành viên xóa chỉ trả về 'void' trong C++ 03. Thay đổi 'i = list.erase (i)' thành 'list.erase (i ++)' sẽ sửa nó. – Casey

+5

@Casey [bạn sai] (http://en.cppreference.com/w/cpp/container/list/erase) – David

-1
for (auto i = list.begin(); i != list.end(); ++i) { 
    if (condition) { 
     list.erase(i); 
     --i; 
    } 
} 
Các vấn đề liên quan