Const Correctness và cạm bẫy
Khái niệm
Phần tiêu đề “Khái niệm”“Const correctness” là thực hành dùng const một cách nhất quán để thể hiện rõ ràng: giá trị nào không nên bị thay đổi. Đây là một trong những thói quen quan trọng nhất để viết code C++ an toàn, nhưng cũng có vài cạm bẫy khi mới làm quen.
Cạm bẫy 1: quên const khiến hàm vô tình sửa đổi dữ liệu
Phần tiêu đề “Cạm bẫy 1: quên const khiến hàm vô tình sửa đổi dữ liệu”#include <string>#include <iostream>
void process(std::string& text) { // Thiếu const - hàm CÓ THỂ sửa đổi text text += "!"; // Vô tình (hoặc cố ý) sửa đổi biến gốc bên ngoài}
int main() { std::string message = "Hello"; process(message); std::cout << message << std::endl; // Hello! - có thể không phải điều bạn muốn return 0;}Nếu hàm chỉ cần đọc dữ liệu, luôn thêm const:
void process(const std::string& text) { // Rõ ràng: hàm KHÔNG được phép sửa đổi text std::cout << text << std::endl; // text += "!"; // LỖI BIÊN DỊCH nếu cố tình sửa - bắt lỗi ngay lúc biên dịch!}Cạm bẫy 2: con trỏ const dễ đọc sai (đã học ở bài “Con trỏ hằng”)
Phần tiêu đề “Cạm bẫy 2: con trỏ const dễ đọc sai (đã học ở bài “Con trỏ hằng”)”const int* ptr1; // Con trỏ đến int HẰNG - không đổi được GIÁ TRỊ, đổi được HƯỚNGint* const ptr2 = &x; // Con trỏ HẰNG - đổi được GIÁ TRỊ, không đổi được HƯỚNGĐây tiếp tục là nguồn nhầm lẫn phổ biến - luôn đọc từ tên biến lùi dần sang trái để xác định const đang áp dụng cho phần nào.
Cạm bẫy 3: const không “lan truyền” qua con trỏ bên trong
Phần tiêu đề “Cạm bẫy 3: const không “lan truyền” qua con trỏ bên trong”struct Container { int* data;};
void modify(const Container& c) { // c là const... *c.data = 100; // ...NHƯNG vẫn sửa đổi được giá trị mà con trỏ BÊN TRONG c trỏ đến!}const chỉ áp dụng cho chính đối tượng c, không “lan truyền” vào dữ liệu mà một con trỏ thành viên của nó trỏ đến - đây gọi là “const chỉ nông” (shallow const), một cạm bẫy tinh vi cần lưu ý khi struct/class chứa con trỏ.
Vì sao nên làm quen với const correctness sớm?
Phần tiêu đề “Vì sao nên làm quen với const correctness sớm?”- Trình biên dịch bắt lỗi ngay lúc biên dịch nếu code cố tình (hoặc vô tình) sửa đổi dữ liệu không nên sửa
- Người đọc code (kể cả chính bạn sau này) hiểu ngay ý định của hàm chỉ qua chữ ký hàm, không cần đọc toàn bộ thân hàm
- Cho phép trình biên dịch tối ưu hóa tốt hơn trong một số trường hợp
Tóm tắt
Phần tiêu đề “Tóm tắt”Const correctness: dùng
constnhất quán để thể hiện rõ dữ liệu nào không nên bị thay đổi.
- Luôn thêm
const&cho tham số chỉ đọc, đặc biệt với kiểu dữ liệu lớnconsttrên một struct/class chỉ bảo vệ chính đối tượng đó - không tự động bảo vệ dữ liệu mà con trỏ thành viên bên trong nó trỏ đến