Giao diện
🛡️ const Best Practices — Const Correctness
const không chỉ là keyword — nó là contract. Sử dụng const đúng cách giúp compiler bắt bugs, tối ưu code, và communicate intent. Tại sao const quan trọng?
- Bug prevention: Compiler bắt lỗi nếu bạn vô tình modify
- Self-documentation: Code nói rõ "tôi không thay đổi giá trị này"
- Optimization: Compiler có thể optimize aggressive hơn
- Thread safety: const objects an toàn đọc từ nhiều threads
const với Variables
cpp
#include <iostream>
int main() {
const int MAX_SIZE = 100; // Compile-time constant
// MAX_SIZE = 200; // ❌ Error: cannot assign to const
int x = 10;
const int y = x; // Runtime constant (giá trị từ x)
// y = 20; // ❌ Error
std::cout << "MAX_SIZE = " << MAX_SIZE << std::endl;
std::cout << "y = " << y << std::endl;
return 0;
}constexpr (C++11) — Compile-time constant guaranteed
cpp
#include <iostream>
constexpr int square(int x) {
return x * x;
}
int main() {
constexpr int size = square(10); // Computed at compile time!
int arr[size]; // OK: size là compile-time constant
std::cout << "Array size: " << size << std::endl; // 100
return 0;
}const với Function Parameters
Rule 1: const Reference cho Read-only Objects
cpp
#include <iostream>
#include <string>
#include <vector>
// ❌ BAD: Copy toàn bộ string
void printBad(std::string s) {
std::cout << s << std::endl;
}
// ✅ GOOD: Không copy, không modify
void printGood(const std::string& s) {
std::cout << s << std::endl;
// s = "modified"; // ❌ Error: s is const
}
// ✅ Với vector
void processData(const std::vector<int>& data) {
for (const auto& item : data) {
std::cout << item << " ";
}
// data.push_back(100); // ❌ Error: data is const
}Rule 2: const Pointer vs Pointer to const
cpp
#include <iostream>
int main() {
int x = 10, y = 20;
// Pointer to const: Không thể modify giá trị, có thể rebind pointer
const int* ptr1 = &x;
// *ptr1 = 100; // ❌ Error: cannot modify value
ptr1 = &y; // ✅ OK: can rebind pointer
// Const pointer: Có thể modify giá trị, không thể rebind
int* const ptr2 = &x;
*ptr2 = 100; // ✅ OK: can modify value
// ptr2 = &y; // ❌ Error: cannot rebind pointer
// Const pointer to const: Không thể làm gì cả!
const int* const ptr3 = &x;
// *ptr3 = 100; // ❌ Error
// ptr3 = &y; // ❌ Error
return 0;
}Đọc từ phải sang trái:
const int* ptr1 → ptr1 is a pointer to (const int)
→ Giá trị không đổi
int* const ptr2 → ptr2 is a (const pointer) to int
→ Pointer không đổi
const int* const p → p is a (const pointer) to (const int)
→ Cả hai không đổiconst Member Functions
cpp
#include <iostream>
#include <string>
class Person {
private:
std::string name_;
int age_;
public:
Person(const std::string& name, int age)
: name_(name), age_(age) {}
// const member function — không modify object state
std::string getName() const {
// name_ = "changed"; // ❌ Error: this is const
return name_;
}
int getAge() const {
return age_;
}
// Non-const — có thể modify
void setAge(int age) {
age_ = age; // ✅ OK
}
// const function có thể gọi từ const object
void print() const {
std::cout << name_ << ", " << age_ << std::endl;
}
};
int main() {
const Person alice("Alice", 25);
std::cout << alice.getName() << std::endl; // ✅ OK
// alice.setAge(26); // ❌ Error: setAge is non-const
alice.print(); // ✅ OK: print() is const
return 0;
}📌 HPN Standard: const Member Functions
- Getter functions luôn là
const - Nếu function không modify state, đánh dấu
const - Compiler sẽ bắt lỗi nếu bạn quên
const Return Types
Returning const Reference
cpp
#include <iostream>
#include <string>
#include <vector>
class Container {
private:
std::vector<int> data_;
public:
Container() : data_{1, 2, 3, 4, 5} {}
// Return const reference — caller không thể modify
const std::vector<int>& getData() const {
return data_;
}
// Return non-const reference — caller CAN modify
std::vector<int>& getDataMutable() {
return data_;
}
};
int main() {
Container c;
// Read-only access
const auto& data = c.getData();
// data.push_back(6); // ❌ Error: data is const
// Mutable access
auto& mutableData = c.getDataMutable();
mutableData.push_back(6); // ✅ OK
return 0;
}Best Practices Summary
✅ DO:
cpp
// 1. Dùng const reference cho read-only params
void process(const std::string& input);
// 2. Mark member functions const khi applicable
int getValue() const;
// 3. Dùng constexpr cho compile-time constants
constexpr int MAX_SIZE = 100;
// 4. Return const reference để prevent modification
const std::vector<int>& getData() const;
// 5. Prefer const over #define
const int BUFFER_SIZE = 1024; // ✅
// #define BUFFER_SIZE 1024 // ❌ Old C-style❌ DON'T:
cpp
// 1. Đừng return const by value cho primitives (vô nghĩa)
const int getValue(); // ❌ Vô ích, caller vẫn copy
// 2. Đừng quá const-ify (over-engineering)
void func(const int x); // ❌ Vô nghĩa — int đã là copy
// 3. Đừng cast away const trừ khi absolutely necessary
const int* ptr = &x;
int* mutablePtr = const_cast<int*>(ptr); // ⚠️ Dangerous!const-correctness Cheatsheet
| Situation | Pattern | Example |
|---|---|---|
| Read-only param (large) | const T& | void f(const std::string& s) |
| Read-only param (small) | T (by value) | void f(int x) |
| Modify param | T& | void f(std::string& s) |
| Optional param | const T* | void f(const Config* cfg) |
| Getter function | T getX() const | int getAge() const |
| Return reference | const T& | const Data& get() const |
🐛 Bug Hunt Challenge
🐛 Bug Hunt
Đoạn code sau compile được không? Tại sao?
cpp
#include <iostream>
#include <string>
class User {
std::string name_;
public:
User(const std::string& name) : name_(name) {}
std::string& getName() const {
return name_;
}
};
int main() {
const User alice("Alice");
alice.getName() = "Bob"; // ???
return 0;
}💡 Gợi ý
getName() là const function, nhưng return type là gì?
🔍 Giải thích
Compiler Error!
error: cannot convert 'const std::string' to 'std::string&'getName() là const function → this là const pointer → name_ được coi là const → không thể return non-const reference!
Fix:
cpp
const std::string& getName() const { // Return const ref
return name_;
}Hoặc nếu cần mutable access:
cpp
std::string& getName() { // Non-const version
return name_;
}
const std::string& getName() const { // Const version
return name_;
}📚 Tổng kết
| Concept | Key Takeaway |
|---|---|
const T& params | Avoid copy, prevent modification |
const member functions | Callable on const objects |
constexpr | Compile-time constants |
Pointer to const (const T*) | Cannot modify value |
Const pointer (T* const) | Cannot rebind pointer |
Return const T& | Prevent caller modification |
Mantra: "const is your friend. Use it everywhere applicable."
🎉 Hoàn thành Part 2!
Chúc mừng! Bạn đã hoàn thành Part 2: Control Flow & Functions.
Quay lại C++ Engineering để xem các modules tiếp theo.