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

Const Correctness và cạm bẫy

“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ƯỚNG
int* 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

Const correctness: dùng const nhấ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ớn
  • const trê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