const int max = 100; // cannot be reassigned
void print(const std::string& s); // won't modify s
C++
Topics in this category
Casting & Conversions
Compilation & Linking
Concepts & Constraints
Concurrency
Const Correctness
Constexpr & Compile-Time
Coroutines
Enums & Enum Classes
Exception Handling
I/O Streams
Lambda Expressions
Memory Management
Modern C++
Move Semantics
Namespaces
OOP & Classes
Operator Overloading
Preprocessor & Macros
RAII & Smart Pointers
Ranges & Views
C++
Const Correctness
const declares that something won't be modified after initialization. Applied to a variable, it makes it read-only; to a function parameter, it promises not to change the argument; to a member function, it promises not to modify the object. const enables compiler enforcement of immutability, safer interfaces, and certain optimizations.
Real-world example
Passing a large object by const reference documents and enforces that the function won't change it.
References & Pointers
Const Correctness
Const Correctness
A const member function (declared with const after the parameter list) promises not to modify the object's observable state and can be called on const objects. Inside it, member variables are treated as const (unless marked mutable). Marking read-only methods const is core to const-correctness and lets them be used on const instances.
struct Box {
int size() const { return n; } // doesn't modify *this
int n = 0;
};
Real-world example
A getter is marked const so it can be called on a const Box passed to a function.
OOP & Classes
Const Correctness
Const Correctness
'Pointer to const' (const int* p) means the pointed-to value can't be changed through p, but p can point elsewhere. 'Const pointer' (int* const p) means p can't be repointed, but the value can change. 'Const pointer to const' (const int* const p) fixes both. Reading right-to-left clarifies which part is const.
const int* a; // value const, pointer mutable
int* const b = &x; // pointer const, value mutable
const int* const c = &x; // both const
Real-world example
An API returns a const int* so callers can read but not modify the internal buffer, while reusing the pointer.
References & Pointers
Const Correctness
Const Correctness
mutable allows a member variable to be modified even inside a const member function (or of a const object). It's used for members that don't affect the object's logical/observable state—caches, memoized values, mutexes, or usage counters—so a logically-const method can still update them.
struct Cache {
int get() const { hits++; return value; } // hits is mutable
mutable int hits = 0;
int value = 0;
};
Real-world example
A cache's hit counter is mutable so read-only accessors can still increment it.
OOP & Classes
Const Correctness
Const Correctness
Physical (bitwise) constness means no bits of the object change. Logical constness means the object's observable/meaningful state doesn't change, even if some internal bits (like a cache or mutex) do. const member functions guarantee logical constness; mutable members let internal, non-observable state change while preserving logical constness.
// A const method that lazily caches a result maintains
// logical constness while mutating a mutable cache member.
Real-world example
A lazily-computed, cached hash preserves logical constness though the cache member physically changes.
Const Correctness
OOP & Classes
Const Correctness
Passing large objects by const reference (const T&) avoids copying (better performance) while promising not to modify the argument (safer, clearer interface, and callable with temporaries and const objects). It's the standard way to pass read-only parameters that are expensive to copy, like strings and containers.
void process(const std::vector<int>& data); // no copy, read-only
Real-world example
Changing a parameter from by-value to const reference removes a costly copy of a large vector on every call.
References & Pointers
Move Semantics
Const Correctness
You can provide both const and non-const overloads of a member function; the compiler picks the const version for const objects and the non-const version for non-const objects. This is common for accessors that return a const reference for const objects and a mutable reference otherwise, avoiding code duplication (or using a const_cast helper).
struct V {
int& at(int i) { return d[i]; }
const int& at(int i) const { return d[i]; }
int d[10];
};
Real-world example
A container's operator[] has const and non-const overloads so const containers return read-only references.
Operator Overloading
OOP & Classes
Const Correctness
const_cast adds or removes const/volatile qualifiers from a pointer or reference. Removing const to modify an object that is genuinely const is undefined behavior; const_cast is only safe to remove const you know was added artificially (e.g., interfacing with a legacy non-const API on an object that is actually mutable). It's a code smell to be used sparingly.
void legacy(char* s);
void wrap(const char* s) { legacy(const_cast<char*>(s)); } // only if legacy won't modify
Real-world example
const_cast bridges to a legacy C API that lacks const, on data known to be mutable.
Casting & Conversions
Const Correctness
Const Correctness
A const reference (const T&) is a reference through which the referent can't be modified. It's useful for read-only aliasing without copying, for function parameters, and because a const reference can bind to a temporary (extending its lifetime to the reference's scope), which a non-const lvalue reference cannot.
const std::string& r = std::string("temp"); // binds temporary
Real-world example
A function takes const std::string& so it can be called with both variables and string literals without copying.
References & Pointers
Const Correctness
Const Correctness
When an object is const, its non-mutable members are treated as const, so member functions called on them must be const. However, if a member is a raw pointer, const only applies to the pointer itself, not the pointee—so a const method can still modify what a member pointer points to. std::experimental::propagate_const (or a wrapper) can extend constness to the pointee.
struct S {
int* p;
void f() const { *p = 5; } // allowed: pointee not const
};
Real-world example
A const method unexpectedly mutates data via a member raw pointer because const doesn't propagate to the pointee.
References & Pointers
Const Correctness
Const Correctness