Truy cập mảng ngoài phạm vi (không báo lỗi!)
Vấn đề
Phần tiêu đề “Vấn đề”Khác với nhiều ngôn ngữ luôn kiểm tra chỉ số và ném lỗi rõ ràng khi vượt phạm vi, mảng C-style và operator[] của std::vector không kiểm tra gì cả:
int numbers[5] = {1, 2, 3, 4, 5};
std::cout << numbers[10] << std::endl; // KHÔNG báo lỗi biên dịch, KHÔNG crash ngay lập tức!// In ra một giá trị RÁC - dữ liệu ngẫu nhiên đang nằm ở vùng nhớ đó
numbers[10] = 100; // CÀNG NGUY HIỂM HƠN - ghi đè lên vùng nhớ không thuộc về mảng này!Vì sao nguy hiểm hơn một lỗi thông thường?
Phần tiêu đề “Vì sao nguy hiểm hơn một lỗi thông thường?”Ghi đè ngoài phạm vi có thể âm thầm phá hỏng dữ liệu của một biến hoàn toàn không liên quan nằm gần đó trong bộ nhớ - khiến chương trình cho ra kết quả sai ở một chỗ hoàn toàn khác, rất khó liên hệ ngược lại nguyên nhân thực sự.
int numbers[3] = {1, 2, 3};int important_flag = 1; // Biến này TÌNH CỜ nằm ngay sau numbers trong bộ nhớ
numbers[5] = 999; // Có thể vô tình ghi đè lên important_flag!// important_flag giờ có thể mang giá trị không mong muốn - lỗi rất khó debugstd::vector cũng có hành vi tương tự với []:
#include <vector>std::vector<int> v = {1, 2, 3};std::cout << v[10] << std::endl; // Undefined behavior - KHÔNG ném exceptionGiải pháp: dùng .at() để có kiểm tra an toàn
Phần tiêu đề “Giải pháp: dùng .at() để có kiểm tra an toàn”#include <vector>#include <iostream>#include <stdexcept>
int main() { std::vector<int> v = {1, 2, 3};
try { std::cout << v.at(10) << std::endl; // .at() CÓ kiểm tra, ném std::out_of_range } catch (const std::out_of_range& e) { std::cout << "Loi: " << e.what() << std::endl; }
return 0;}.at() chậm hơn [] một chút (vì phải kiểm tra phạm vi mỗi lần truy cập), nên [] thường được ưu tiên trong code cần hiệu năng cao khi bạn đã chắc chắn chỉ số hợp lệ (ví dụ trong vòng lặp for (i = 0; i < v.size(); i++)).
Công cụ hỗ trợ phát hiện
Phần tiêu đề “Công cụ hỗ trợ phát hiện”Biên dịch với Address Sanitizer (-fsanitize=address) giúp phát hiện ngay lập tức khi chương trình truy cập ngoài phạm vi, thay vì để lỗi âm thầm gây hậu quả về sau:
g++ -fsanitize=address -g program.cpp -o programTóm tắt
Phần tiêu đề “Tóm tắt”
[]không kiểm tra phạm vi - truy cập ngoài phạm vi là undefined behavior, có thể “chạy được” một cách nguy hiểm mà không báo lỗi ngay.
- Dùng
.at()khi cần đảm bảo an toàn (sẽ ném exception nếu sai)- Dùng
[]khi hiệu năng quan trọng và chỉ số chắc chắn hợp lệ- Biên dịch với Address Sanitizer khi debug để phát hiện lỗi này sớm