auto không tự giữ lại reference/const
Vấn đề
Phần tiêu đề “Vấn đề”Bài “auto và suy luận kiểu dữ liệu” đã đề cập ngắn gọn: auto mặc định bỏ qua const và tham chiếu (&) của giá trị ban đầu. Đây là cạm bẫy phổ biến, đặc biệt khi dùng auto với range-based for trên container lớn.
Cạm bẫy: auto trong range-based for tạo ra bản sao không mong muốn
Phần tiêu đề “Cạm bẫy: auto trong range-based for tạo ra bản sao không mong muốn”#include <vector>#include <string>#include <iostream>
int main() { std::vector<std::string> names = {"Alice", "Bob", "Charlie"};
for (auto name : names) { // auto suy luận là std::string - TẠO BẢN SAO cho mỗi phần tử! name += "!"; // Chỉ sửa đổi BẢN SAO, không ảnh hưởng đến names gốc }
for (const auto& name : names) { // In ra names gốc - vẫn KHÔNG có dấu "!" std::cout << name << " "; } // Alice Bob Charlie (không đổi)
return 0;}Với container chứa dữ liệu lớn (chuỗi dài, struct lớn), việc vô tình sao chép từng phần tử trong vòng lặp gây lãng phí hiệu năng đáng kể mà không hề có cảnh báo nào.
Giải pháp: chỉ định rõ &/const& khi cần
Phần tiêu đề “Giải pháp: chỉ định rõ &/const& khi cần”#include <vector>#include <string>#include <iostream>
int main() { std::vector<std::string> names = {"Alice", "Bob", "Charlie"};
// Chỉ đọc, không sao chép - hiệu quả nhất khi không cần sửa đổi for (const auto& name : names) { std::cout << name << " "; }
// Cần sửa đổi trực tiếp phần tử trong container for (auto& name : names) { name += "!"; }
for (const auto& name : names) { std::cout << name << " "; } // Alice! Bob! Charlie!
return 0;}Quy tắc chọn giữa auto, auto&, const auto&
Phần tiêu đề “Quy tắc chọn giữa auto, auto&, const auto&”| Cú pháp | Khi nào dùng |
|---|---|
auto x = value |
Cần một bản sao độc lập, không quan tâm dữ liệu gốc |
auto& x = value |
Cần sửa đổi trực tiếp giá trị gốc |
const auto& x = value |
Chỉ cần đọc, muốn tránh sao chép dữ liệu lớn (lựa chọn mặc định tốt nhất cho range-based for) |
Ví dụ khác: auto với hàm trả về tham chiếu
Phần tiêu đề “Ví dụ khác: auto với hàm trả về tham chiếu”#include <vector>
std::vector<int> numbers = {1, 2, 3};
int& get_first() { return numbers[0];}
auto x = get_first(); // x là int (BẢN SAO), không phải int&!auto& y = get_first(); // y là int& - tham chiếu THỰC SỰ đến numbers[0]
y = 100; // Sửa đổi trực tiếp numbers[0]// x = 100; // Chỉ sửa bản sao độc lập, KHÔNG ảnh hưởng đến numbersTóm tắt
Phần tiêu đề “Tóm tắt”
automặc định suy luận kiểu giá trị (bỏ quaconstvà&) - dùngauto&/const auto&khi cần giữ lại tham chiếu.
- Trong range-based for,
const auto&là lựa chọn an toàn và hiệu quả nhất khi chỉ cần đọc dữ liệuauto&khi cần sửa đổi trực tiếp phần tử trong container