Bỏ qua để đến nội dung

Iterator trong C++

Iterator là một đối tượng dùng để “trỏ” đến một phần tử trong container (vector, map, set…) và di chuyển qua các phần tử khác - hoạt động giống con trỏ, và đây không phải sự trùng hợp: iterator được thiết kế dựa trên khái niệm con trỏ.

#include <vector>
#include <iostream>
int main() {
std::vector<int> numbers = {10, 20, 30};
std::vector<int>::iterator it = numbers.begin(); // Iterator trỏ đến phần tử đầu tiên
std::cout << *it << std::endl; // 10 - dereference giống con trỏ
++it; // Di chuyển sang phần tử tiếp theo
std::cout << *it << std::endl; // 20
return 0;
}
  • .begin(): trả về iterator trỏ đến phần tử đầu tiên
  • .end(): trả về iterator trỏ đến vị trí ngay sau phần tử cuối cùng (không phải phần tử cuối!)
#include <vector>
#include <iostream>
int main() {
std::vector<int> numbers = {10, 20, 30, 40};
for (std::vector<int>::iterator it = numbers.begin(); it != numbers.end(); ++it) {
std::cout << *it << " ";
}
// 10 20 30 40
return 0;
}

Dùng auto để tránh phải viết kiểu iterator dài dòng:

for (auto it = numbers.begin(); it != numbers.end(); ++it) {
std::cout << *it << " ";
}

Đây thực chất là những gì đang diễn ra “bên dưới” khi bạn dùng range-based for (for (int n : numbers)) - range-based for chỉ là cú pháp gọn hơn của vòng lặp iterator này.

#include <map>
#include <iostream>
int main() {
std::map<std::string, int> ages = {{"Alice", 25}, {"Bob", 30}};
for (auto it = ages.begin(); it != ages.end(); ++it) {
std::cout << it->first << ": " << it->second << std::endl; // -> vì it trỏ đến một pair
}
return 0;
}

Nhiều phương thức của container trả về hoặc yêu cầu iterator làm tham số - đã xuất hiện ở các bài trước mà không giải thích chi tiết:

#include <vector>
#include <algorithm>
#include <iostream>
int main() {
std::vector<int> numbers = {10, 20, 30, 40};
auto it = std::find(numbers.begin(), numbers.end(), 30); // Tìm giá trị 30
if (it != numbers.end()) {
std::cout << "Tim thay tai vi tri: " << (it - numbers.begin()) << std::endl; // 2
numbers.erase(it); // Xóa phần tử tại vị trí iterator trỏ đến
}
for (int n : numbers) {
std::cout << n << " ";
}
// 10 20 40
return 0;
}
std::vector<int> numbers = {1, 2, 3};
for (std::vector<int>::const_iterator it = numbers.cbegin(); it != numbers.cend(); ++it) {
std::cout << *it << " ";
// *it = 100; // LỖI! const_iterator không cho phép sửa đổi
}

Iterator cung cấp một giao diện thống nhất để duyệt qua mọi loại container, dù cấu trúc dữ liệu bên dưới hoàn toàn khác nhau (vector liên tục trong bộ nhớ, map là cây nhị phân, set cũng vậy). Nhờ đó, các hàm thuật toán trong <algorithm> (như std::sort, std::find) có thể hoạt động với bất kỳ container nào miễn là nó cung cấp iterator hợp lệ.

  • Iterator là đối tượng “trỏ” đến một phần tử trong container, hỗ trợ * (dereference) và ++ (di chuyển) giống con trỏ
  • .begin() trỏ đến phần tử đầu tiên; .end() trỏ đến vị trí ngay sau phần tử cuối cùng
  • Range-based for thực chất là cú pháp gọn hơn của vòng lặp dùng iterator
  • Nhiều hàm thuật toán (std::find, std::sort…) hoạt động thông qua iterator, giúp dùng chung được cho nhiều loại container