Tôi cần phải trải qua một tập hợp và loại bỏ các yếu tố đáp ứng tiêu chí được xác định trước.
Đây là mã kiểm tra tôi đã viết:
#include <set>
#include <algorithm>
void printElement(int value) {
std::cout << value << " ";
}
int main() {
int initNum[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
std::set<int> numbers(initNum, initNum + 10);
// print '0 1 2 3 4 5 6 7 8 9'
std::for_each(numbers.begin(), numbers.end(), printElement);
std::set<int>::iterator it = numbers.begin();
// iterate through the set and erase all even numbers
for (; it != numbers.end(); ++it) {
int n = *it;
if (n % 2 == 0) {
// wouldn't invalidate the iterator?
numbers.erase(it);
}
}
// print '1 3 5 7 9'
std::for_each(numbers.begin(), numbers.end(), printElement);
return 0;
}
Lúc đầu, tôi nghĩ rằng việc xóa một phần tử khỏi tập hợp trong khi lặp qua nó sẽ làm mất hiệu lực của trình vòng lặp và gia số tại vòng lặp for sẽ có hành vi không xác định. Mặc dù, tôi đã thực thi mã kiểm tra này và tất cả đều diễn ra tốt đẹp, và tôi không thể giải thích tại sao.
Câu hỏi của tôi: Đây có phải là hành vi được xác định cho các bộ std hoặc việc triển khai này là cụ thể? Tôi đang sử dụng gcc 4.3.3 trên Ubuntu 10.04 (phiên bản 32 bit).
Cảm ơn!
Giải pháp đề xuất:
Đây có phải là một cách chính xác để lặp và xóa các phần tử khỏi tập hợp?
while(it != numbers.end()) {
int n = *it;
if (n % 2 == 0) {
// post-increment operator returns a copy, then increment
numbers.erase(it++);
} else {
// pre-increment operator increments, then return
++it;
}
}
Chỉnh sửa: GIẢI PHÁP ƯU ĐÃI
Tôi đã tìm ra một giải pháp có vẻ thanh lịch hơn đối với tôi, mặc dù nó hoàn toàn giống nhau.
while(it != numbers.end()) {
// copy the current iterator then increment it
std::set<int>::iterator current = it++;
int n = *current;
if (n % 2 == 0) {
// don't invalidate iterator it, because it is already
// pointing to the next element
numbers.erase(current);
}
}
Nếu có một vài điều kiện kiểm tra bên trong, mỗi một trong số chúng phải tăng vòng lặp. Tôi thích mã này tốt hơn bởi vì trình vòng lặp chỉ được tăng ở một nơi , làm cho mã ít bị lỗi hơn và dễ đọc hơn.
++it
sẽ hiệu quả hơn một chút so với it++
vì nó không yêu cầu sử dụng bản sao tạm thời vô hình của trình vòng lặp. Phiên bản của Kornel trong khi dài hơn đảm bảo rằng các phần tử không được lọc được lặp lại một cách hiệu quả nhất.