Why Constants Exist
A constant is a value you promise never to change after you set it. Marking something const does two jobs at once: it documents your intent to anyone reading the code, and it lets the compiler enforce that intent - any line that tries to modify the value becomes a compile error rather than a silent runtime bug.
Where the auto keyword let the compiler infer a variable's type, const constrains what you can do with that variable. The two combine freely: const auto limit = 100; is a read-only int.
Declaring a const Value
Put const before the type. A const variable must be initialized on the same line, because there is no later moment when you are allowed to assign to it.
Uncomment the assignment and the program will not compile - the compiler reports "assignment of read-only variable". That is exactly the point: the mistake is caught before the program ever runs.
A common beginner habit carried from C is #define MAX_USERS 100. Avoid it. A macro is a blind text substitution with no type and no respect for scope, so it cannot be inspected in a debugger and produces confusing error messages. A const (or constexpr) variable is type-checked and scoped like any other.
const vs constexpr
Both keywords give you a value that cannot change, but they answer different questions. const says "this never changes after it is set". constexpr says the stronger "this can be computed at compile time" - and anything constexpr is automatically const too.
The rule of thumb: reach for constexpr whenever the value is a fixed literal or a calculation the compiler can do (array sizes, buffer lengths, switch labels, template arguments). Use plain const when the value is decided at runtime but should not change afterward - like a const copy of a function argument.
Since C++20 there is also consteval, used on functions that must run at compile time:
consteval int square(int x) { return x * x; }
constexpr int area = square(8); // computed during compilation
A constexpr function may run at compile time; a consteval function always must, or it is an error.
Pointers and const: Read Right-to-Left
This is where const trips people up, because the keyword can sit on either side of the * and the two meanings are opposite. The trick is to read the declaration from right to left.
Read int* const p2 right-to-left: "p2 is a const pointer to int". Read const int* p1 as "p1 is a pointer to const int". Get this wrong and you will spend real time confused by an error that says you cannot modify something you thought was mutable.
A practical gotcha: never take the address of a const and cast the const away to modify the underlying object. Doing so is undefined behavior if the original object was truly const, and the compiler is free to assume the value never changes - your "write" may simply be ignored.
const References as Function Parameters
The most common everyday use of const is passing large objects by reference without copying them. A const& parameter avoids the copy and promises the function will not modify the caller's argument.
Pass-by-const& is the default choice for any parameter bigger than a couple of bytes (strings, vectors, your own classes). Note it also lets the function accept a temporary like "Grace" - a plain non-const reference cannot bind to a temporary, so dropping the const here would reject that second call.
const Member Functions
When you write a class, mark any method that does not modify the object with a trailing const. This is what makes the method callable on const instances and on const& parameters - without it, you cannot read your own object through a const handle.
The discipline of marking read-only methods const is called const correctness. Get it right early - a method that should have been const is easy to add, but retrofitting const across a large codebase later is painful because every caller through a const reference depends on it.
Next: Operators
Now that your values can be locked down with const, the next step is doing things with them. The operators page covers arithmetic, comparison, logical, and assignment operators - including the gotchas around integer division, operator precedence, and how const interacts with the assignment operators you are not allowed to use.
Frequently Asked Questions
What is the difference between const and constexpr in C++?
const means the value cannot change after initialization, but it may be computed at runtime. constexpr is stronger: it guarantees the value can be computed at compile time, so it can be used where a compile-time constant is required (array sizes, template arguments, switch labels). Every constexpr object is also const, but not every const object is constexpr.
How do I declare a constant in C++?
Put const before the type and give it a value: const int maxUsers = 100;. A const variable must be initialized when declared, because you can never assign to it later. For compile-time constants prefer constexpr int maxUsers = 100;. Avoid the old C-style #define macro - it has no type and ignores scope.
What does a const pointer mean in C++?
It depends on where const sits. const int* p is a pointer to const - you can repoint p, but you cannot change *p. int* const p is a const pointer - you can change *p, but you cannot repoint p. Read the declaration right-to-left: int* const is "const pointer to int".