auto và suy luận kiểu dữ liệu
Từ khóa auto (C++11) cho phép trình biên dịch tự suy luận kiểu dữ liệu của một biến dựa vào giá trị khởi tạo, giúp code ngắn gọn hơn mà vẫn giữ nguyên tính an toàn của kiểu tĩnh.
auto cơ bản
Phần tiêu đề “auto cơ bản”#include <iostream>
int main() { auto x = 10; // Trình biên dịch suy luận: x là int auto y = 3.14; // y là double auto name = std::string("Alice"); // name là std::string
std::cout << x << " " << y << " " << name << std::endl;
return 0;}⚠️ Quan trọng: auto không có nghĩa là kiểu dữ liệu động. Kiểu dữ liệu vẫn được xác định một lần duy nhất tại thời điểm biên dịch, dựa vào giá trị khởi tạo, và không thể thay đổi sau đó:
auto x = 10;// x = "hello"; // LỖI BIÊN DỊCH! x đã được suy luận là int, không thể chứa chuỗix = 20; // OK, vẫn là intauto phải được khởi tạo ngay
Phần tiêu đề “auto phải được khởi tạo ngay”Vì auto cần một giá trị để suy luận kiểu, nó bắt buộc phải khởi tạo ngay khi khai báo:
// int a; // OK - int có thể khai báo mà chưa khởi tạo// auto b; // LỖI! Không có giá trị nào để suy luận kiểuauto c = 5; // OKKhi nào auto thực sự hữu ích?
Phần tiêu đề “Khi nào auto thực sự hữu ích?”1. Kiểu dữ liệu dài dòng, đặc biệt là iterator
Phần tiêu đề “1. Kiểu dữ liệu dài dòng, đặc biệt là iterator”#include <vector>#include <map>#include <string>
std::map<std::string, std::vector<int>> data;
// Không dùng auto - rất dài dòngstd::map<std::string, std::vector<int>>::iterator it1 = data.begin();
// Dùng auto - ngắn gọn hơn nhiềuauto it2 = data.begin();2. Kiểu trả về phức tạp từ hàm thư viện
Phần tiêu đề “2. Kiểu trả về phức tạp từ hàm thư viện”#include <vector>
std::vector<int> numbers = {1, 2, 3};
auto it = numbers.begin(); // Không cần nhớ chính xác kiểu iterator trả về là gì3. Range-based for
Phần tiêu đề “3. Range-based for”#include <vector>#include <iostream>
int main() { std::vector<int> numbers = {1, 2, 3};
for (auto n : numbers) { // Không cần viết rõ "int n" std::cout << n << " "; }
return 0;}auto với tham chiếu và const
Phần tiêu đề “auto với tham chiếu và const”Mặc định, auto sẽ bỏ qua const và tham chiếu (&) của giá trị ban đầu - cần chỉ định rõ nếu muốn giữ lại:
#include <iostream>
int main() { int x = 10; const int& ref = x;
auto a = ref; // a là int (bản SAO), KHÔNG phải const int& auto& b = ref; // b là const int& (giữ lại reference và const)
a = 100; // OK - a chỉ là bản sao độc lập std::cout << x << std::endl; // 10 (không đổi)
return 0;}Khi nào KHÔNG nên lạm dụng auto?
Phần tiêu đề “Khi nào KHÔNG nên lạm dụng auto?”auto x = get_something(); // Kiểu dữ liệu của x là gì? Phải xem định nghĩa get_something() mới biết!
int count = get_count(); // Rõ ràng ngay: count là số nguyênDùng auto quá nhiều, đặc biệt với tên hàm không rõ ràng, có thể khiến code khó đọc hơn vì người đọc không biết ngay kiểu dữ liệu là gì. Quy tắc chung: dùng auto khi kiểu dữ liệu đã rõ ràng từ ngữ cảnh (ví dụ vế phải của phép gán), hoặc khi kiểu quá dài dòng để viết ra (như iterator).
Tổng kết
Phần tiêu đề “Tổng kết”autođể trình biên dịch tự suy luận kiểu dữ liệu dựa vào giá trị khởi tạo, tại thời điểm biên dịch- Biến khai báo với
autovẫn có kiểu tĩnh, cố định, được xác định ngay lúc biên dịch autobắt buộc phải khởi tạo ngay khi khai báo- Hữu ích nhất với kiểu dữ liệu dài dòng (iterator, kiểu trả về phức tạp); tránh lạm dụng khi làm giảm khả năng đọc code