C++ const Complete Guide | 'const Correctness' Practical Usage
이 글의 핵심
const-correctness is a C++ convention that reduces bugs by compiler-enforcing values and APIs that should not change. This guide explains const variables, member functions, pointer declarations, and mutable combinations with examples.
const Variables
const expresses “immutable” and is recommended in code review. Used with mutable, you can have exceptionally modifiable members like cache and locks. Combined with function basics and smart pointers, you can create read-only interfaces.
const int x = 10;
// x = 20; // Error: const variable cannot be modified
const int y; // Error: const must be initialized at declaration
const Functions
Here is detailed implementation code using C++. Define a class to encapsulate data and functionality. Understand the role of each part while examining the code.
class Point {
private:
int x, y;
public:
Point(int x, int y) : x(x), y(y) {}
// const member function (does not change object state)
int getX() const { return x; }
int getY() const { return y; }
// non-const member function
void setX(int newX) { x = newX; }
};
int main() {
const Point p(10, 20);
cout << p.getX() << endl; // OK
// p.setX(30); // Error: const object cannot call non-const function
}
const Pointers
const Pointer Patterns
| Declaration | Modify Pointer | Modify Value | Read As |
|---|---|---|---|
const int* ptr | ✅ | ❌ | “pointer to const int” |
int* const ptr | ❌ | ✅ | “const pointer to int” |
const int* const ptr | ❌ | ❌ | “const pointer to const int” |
int const* ptr | ✅ | ❌ | Same as const int* |
Here is detailed implementation code using C++. Understand the role of each part while examining the code.
int x = 10;
int y = 20;
// 1. Value pointed to is const
const int* ptr1 = &x;
// *ptr1 = 20; // Error
ptr1 = &y; // OK
// 2. Pointer itself is const
int* const ptr2 = &x;
*ptr2 = 20; // OK
// ptr2 = &y; // Error
// 3. Both const
const int* const ptr3 = &x;
// *ptr3 = 20; // Error
// ptr3 = &y; // Error
Memorization tip: What’s to the right of const is const
const Pointer Visualization
Below is an implementation example using mermaid. Try running the code directly to check its operation.
graph TD
A[const int* ptr] --> B[ptr modifiable]
A --> C[*ptr not modifiable]
D[int* const ptr] --> E[ptr not modifiable]
D --> F[*ptr modifiable]
G[const int* const ptr] --> H[ptr not modifiable]
G --> I[*ptr not modifiable]
const Reference
Below is an implementation example using C++. Process data with loops. Understand the role of each part while examining the code.
void process(const vector<int>& v) {
// Only read v (no copy)
for (int x : v) {
cout << x << " ";
}
// v.push_back(10); // Error
}
int main() {
vector<int> data = {1, 2, 3};
process(data); // Pass without copy
}
mutable
mutable Usage Scenarios
| Scenario | Example | Reason |
|---|---|---|
| Caching | Store calculation result | Logically const, physically changed |
| Statistics | Count access count | Observation-only action |
| Synchronization | mutable mutex | Lock is not logical state |
| Lazy initialization | Initialize on first access | Read action but internal change |
Here is detailed implementation code using C++. Define a class to encapsulate data and functionality. Understand the role of each part while examining the code.
class Cache {
private:
mutable int accessCount; // Modifiable even in const function
int value;
public:
Cache(int v) : value(v), accessCount(0) {}
int getValue() const {
accessCount++; // OK: mutable
return value;
}
int getAccessCount() const {
return accessCount;
}
};
int main() {
const Cache cache(42);
cout << cache.getValue() << endl; // accessCount incremented
cout << cache.getAccessCount() << endl; // 1
}
Practical Examples
Example 1: const Correctness
Here is detailed implementation code using C++. Define a class to encapsulate data and functionality. Understand the role of each part while examining the code.
class String {
private:
char* data;
size_t length;
public:
String(const char* str) {
length = strlen(str);
data = new char[length + 1];
strcpy(data, str);
}
~String() {
delete[] data;
}
// const version
const char* c_str() const {
return data;
}
// non-const version
char* c_str() {
return data;
}
size_t size() const {
return length;
}
};
void print(const String& s) {
cout << s.c_str() << endl; // Calls const version
}
Example 2: const and Iterators
Here is detailed implementation code using C++. Import the necessary modules and process data with loops. Understand the role of each part while examining the code.
#include <vector>
using namespace std;
void process(const vector<int>& v) {
// Use const_iterator
for (vector<int>::const_iterator it = v.begin();
it != v.end(); ++it) {
cout << *it << " ";
// *it = 10; // Error
}
// Or use auto
for (auto it = v.cbegin(); it != v.cend(); ++it) {
cout << *it << " ";
}
}
Example 3: const and Thread Safety
Here is detailed implementation code using C++. Import the necessary modules and define a class to encapsulate data and functionality. Understand the role of each part while examining the code.
#include <mutex>
class ThreadSafeCounter {
private:
mutable mutex mtx; // Can lock even in const function
int count;
public:
ThreadSafeCounter() : count(0) {}
void increment() {
lock_guard<mutex> lock(mtx);
count++;
}
int getCount() const {
lock_guard<mutex> lock(mtx); // OK: mutable
return count;
}
};
Summary
Key Points
- const variables: Cannot be modified after initialization
- const functions: Do not modify object state
- const pointers: Four patterns (pointer/value const)
- const reference: Pass without copy
- mutable: Modifiable in const functions
Best Practices
- ✅ Use const for read-only parameters
- ✅ Mark member functions const when possible
- ✅ Use const reference for large objects
- ✅ Use mutable for cache/statistics
- ❌ Don’t cast away const
- ❌ Don’t abuse mutable
Related Articles
Master const correctness for safer C++ code! 🚀