Language[lang]
const in C++: variables, pointers, references, methods
- Section
- Language [lang]
- Standard
- C++17
- Compilers
- MSVC 19.44, Clang 19.1 (MSVC STL), GCC 16.2, Clang 23.1 (libc++)
- Published
- Length
- 7 min read
Abstract
In C++, const makes something read-only: a const variable gets its value where it is declared, and the compiler rejects any direct change to it. Read a pointer declaration right to left: a pointer to a const int cannot change the int, and a const pointer cannot point elsewhere. A const reference parameter reads the caller’s object without copying it, a const member function promises not to change its object, and constexpr adds that the value is known when the program is compiled.

In C++, const marks something as read-only: once a const variable has its value, the compiler rejects any direct change to it. The same keyword makes a pointer or a reference read-only for what it refers to, and on a member function it promises not to change the object. Use it wherever a value should not change.
A login limit, in a whole program:
#include <iostream>
int main() {
const int max_attempts = 3;
for (int attempt = 1; attempt <= max_attempts; ++attempt) {
std::cout << "Attempt " << attempt << " of " << max_attempts
<< '\n';
}
}— end example]
It printed:
Attempt 1 of 3
Attempt 2 of 3
Attempt 3 of 3— end example]
Try to change the limit, and the program no longer compiles:
const int max_attempts = 3;
max_attempts = 5; // error: max_attempts is const— end example]
Clang said:
error: cannot assign to variable 'max_attempts' with const-qualified type 'const int'— end example]
The samples are standard C++17, built with MSVC 19.44, Clang 19.1 (MSVC STL), GCC 16.2 and Clang 23.1 (libc++). All four accepted and rejected the same lines; Since When lists the compiler releases for each standard.
How do you declare a const variable?
Write const before the type and give the value in the same declaration, as const int max_attempts = 3; does; int const means the same. A const int with no value does not compile, since nothing could set it later (default-initialization): const int limit; stopped all four, GCC with uninitialized 'const limit'.
A const member of a class cannot be assigned later either. It takes its value from a default in the class, as in const int attempts_ = 3;, or in the constructor’s member initializer list, the part after the colon (how a C++ constructor sets its members).
What is the difference between const int* and int* const?
Read the declaration from right to left: const int* p is a pointer to a const int, and int* const p is a const pointer to an int. A pointer is a variable that holds the address of another (&balance is the address of balance, and *view the int that view points to). const before the * applies to the int, after it to the pointer itself, so int const* p is the same as const int* p (pointer declarations):
int balance = 100;
int savings = 500;
const int* view = &balance; // pointer to a const int
view = &savings; // fine: view points elsewhere
std::cout << *view << '\n'; // 500
int* const account = &balance; // const pointer to an int
*account = 150; // fine: the int changes
std::cout << balance << '\n'; // 150
const int* const fixed = &savings; // both are locked
std::cout << *fixed << '\n'; // 500— end example]
All four printed 500, 150 and 500. Each pointer refuses the other operation. Writing through view does not compile:
*view = 200; // error: the int is const through view— end example]
GCC said assignment of read-only location '* view'. Pointing account at another int fails too:
account = &savings; // error: the pointer itself is const— end example]
GCC: assignment of read-only variable 'account'.

| Declaration | Reads as | Change the int through it? | Point elsewhere? |
|---|---|---|---|
const int* p |
pointer to a const int | no | yes |
int* const p |
const pointer to an int | yes | no |
const int* const p |
const pointer to a const int | no | no |
What is a const reference?
A const reference lets a function read the caller’s object without copying it and without being able to change it. A reference is another name for an existing object, so const std:: refers to the caller’s own string: nothing is copied, and name is read-only inside the function.
#include <iostream>
#include <string>
void greet(const std::string& name) {
std::cout << "Hello, " << name << '\n';
}
int main() {
std::string owner = "Ada";
greet(owner); // name refers to owner: no copy
greet("Grace"); // a temporary std::string binds to name
}— end example]
It printed Hello, Ada and Hello, Grace. A const reference also accepts a literal: for greet("Grace") C++ builds a temporary std::string for name to refer to (reference initialization). A plain std::string& name would not: C++ binds a temporary to a const reference, not to a plain one, and all four rejected greet("Grace") with that parameter. Inside greet, name += "!"; stopped all four; MSVC said binary '+=': no operator found which takes a left-hand operand of type 'const std::.
Whether a parameter should be a const reference or a plain value depends on its type and on what the function does with it; pass by value or by const reference has the rule.
What is a const member function?
A const member function promises not to change the object it is called on: write const after the parameter list, as in int balance() const. A member function is a function declared inside a class, and these are what “const functions” means in C++. A free function, one outside any class, cannot be const: there is no object for the promise to cover.
class Account {
public:
int balance() const { return balance_; } // only reads
void deposit(int amount) { balance_ += amount; }
private:
int balance_ = 0;
};
void print_balance(const Account& account) {
std::cout << "Balance: " << account.balance() << '\n';
}— end example]
It printed Balance: 100 after a deposit of 100. Only const member functions can be called on a const object or through a const reference, so print_balance can call balance() but not deposit():
void add_bonus(const Account& account) {
account.deposit(10); // error: deposit() is not const
}— end example]
Clang said:
error: 'this' argument to member function 'deposit' has type 'const Account', but function is not marked const— end example]
this is the pointer to the object a member function was called on. Through a const Account& that object is const, and deposit() does not promise to leave it alone, so the call is refused.
The compiler holds a const member function to its promise, too: balance_ -= 1; inside balance() const stopped all four, MSVC with 'balance_' cannot be modified because it is being accessed through a const object. Defined outside the class, the function needs const in both its declaration and its definition. Mark every member function that only reads as const, or code holding a const reference cannot call it (const-qualified member functions).
const vs constexpr: what is the difference?
const means a value does not change once it is set, and that value may be worked out while the program runs. constexpr means the value is known when the program is compiled, so it can go where the compiler needs a number, such as an array size or a static_assert, a check the compiler makes:
const int typed = read_number(); // fixed when the program runs
constexpr int size = 10; // known when it is compiled
int deposits[size] = {}; // an array size must be known
static_assert(size == 10); // checked by the compiler
std::cout << typed << ' ' << std::size(deposits) << '\n';— end example]
Here read_number() reads an int typed in; given 7, all four printed 7 10. A const int set from a constant, such as const int size = 10;, can be an array size too; what constexpr adds is the guarantee: constexpr int typed = read_number(); does not compile, and Clang said constexpr variable 'typed' must be initialized by a constant expression.
A constexpr variable is const as well ([dcl.constexpr]), so choose by when the value is known: constexpr for one the compiler can work out, const for one the program reads or computes as it runs.
When should you use const?
By default, wherever a value is not meant to change: “By default, make objects immutable” is the first rule of the C++ Core Guidelines on constants and immutability. Each const is a promise the compiler checks, so a change you did not mean becomes a compile error, as max_attempts = 5; did, instead of a bug you find later.
conston every variable whose value does not change after it is set.- A reference or pointer to const for a parameter the function only reads.
constafter the parameter list of every member function that only reads.constexprfor a value known when the program is compiled.
The Language section has the other answers on the core language.
Questions
Can you change a const variable in C++?
No. The compiler rejects any assignment to a const variable, such as max_attempts = 5;. Writing to a const object through a pointer or reference whose const was removed with a cast is undefined behavior: the standard places no requirement on what the program then does.
What is the difference between const and #define?
A const variable is part of the language: it has a type and a scope, and the compiler checks every use of it. #define is text replacement: the preprocessor swaps the name for its text before the compiler sees the code, with no type and no scope. For a named value in C++, const or constexpr keeps those checks.
Does const go before or after the type?
Either. const int x and int const x declare the same type, which a static_assert confirmed on GCC, Clang and MSVC. With pointers, what matters is which side of the asterisk the const is on: before it, the value is const; after it, the pointer is.
What does mutable mean in C++?
A mutable data member may be changed even inside a const member function or in a const object. It suits a cache or a counter that is not part of the object’s value: a mutable int reads_ that counted the calls to balance() const compiled and counted correctly on GCC, Clang and MSVC.
Can a function parameter be const?
Yes. On a parameter taken by value, const only stops the function changing its own copy, and void f(const int) declares the same function as void f(int). On a reference or pointer to const, such as const std::string& or const int*, const stops the function changing the caller’s object.
Sources
- cv (const and volatile) type qualifierscppreference.com
- Pointer declarationcppreference.com
- Default-initializationcppreference.com
- Reference initializationcppreference.com
- Non-static member functionscppreference.com
- constexpr specifiercppreference.com
- [dcl.type.cv] The cv-qualifiersC++ standard working draft
- Con: Constants and immutabilityC++ Core Guidelines