C++ const Complete Guide | 'const Correctness' Practical Usage

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

DeclarationModify PointerModify ValueRead 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* ptrSame 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

ScenarioExampleReason
CachingStore calculation resultLogically const, physically changed
StatisticsCount access countObservation-only action
Synchronizationmutable mutexLock is not logical state
Lazy initializationInitialize on first accessRead 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

  1. const variables: Cannot be modified after initialization
  2. const functions: Do not modify object state
  3. const pointers: Four patterns (pointer/value const)
  4. const reference: Pass without copy
  5. 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

Master const correctness for safer C++ code! 🚀