Beginner 7 min

Const Correctness

Using const to specify immutability and prevent accidental modifications

Learn how to use const to make your intentions clear and prevent bugs by specifying which values should not change.

A Simple Example

#include <iostream>
#include <string>

int main() {
    const int max{100};  // Cannot change max
    // max = 200;  // ERROR! Cannot modify const

    // Const reference parameter
    const std::string message{"Hello"};
    // message = "Bye";  // ERROR! Cannot modify const

    int value{42};
    const int& ref{value};  // Const reference to non-const value
    // ref = 50;  // ERROR! Cannot modify through const reference
    value = 50;  // OK! Can modify value directly

    return 0;
}

Breaking It Down

Const Variables: const int x{10};

  • What it does: Creates a variable whose value cannot be changed after initialization
  • Must initialize: const int x{10}; is required - can't declare without a value
  • Compiler enforced: Trying to modify const variables causes compile-time errors
  • Remember: Use const for values that should never change like max limits, pi, etc.

Const References: const Type& param

  • What it does: Prevents modifying the referenced object through this reference
  • Best for parameters: Avoids copying large objects while preventing modification
  • Performance + safety: Gets benefits of pass-by-reference without the risk
  • Remember: Use const Type& for read-only function parameters

Const Pointers: Two Flavors

  • const int* p: Pointer to const int - can't change value through pointer
  • int* const p: Const pointer to int - can't change where pointer points
  • const int* const p: Both const - can't change value or pointer
  • Remember: Read right-to-left: const int* = "pointer to const int"

Const Member Functions: void func() const

  • What it does: Promises not to modify the object
  • Syntax: void getName() const { return name; }
  • Can call on const objects: Only const member functions can be called on const objects
  • Remember: Mark getter methods as const to allow them on const objects

Why This Matters

  • Prevents bugs by making intentions clear - the compiler enforces that const values don't change.
  • Enables compiler optimizations - const allows the compiler to make better optimization decisions.
  • Documents which functions modify state - seeing const in a signature tells you the function won't modify the parameter.

Critical Insight

const references give you the performance of passing by reference with the safety of passing by value. Best of both worlds!

When you pass by value, the entire object is copied (slow for large objects). When you pass by reference, modifications affect the original. But const Type& gives you no copying AND no accidental modifications - it's the perfect choice for read-only parameters.

Best Practices

Use const by default: Start with const and remove it only if you need to modify the value. This prevents accidental changes.

Const references for parameters: Use const Type& for read-only parameters of large objects to avoid copying.

Mark getters as const: Member functions that don't modify the object should be marked const so they work with const objects.

Read const pointers carefully: const int* p (pointer to const) is different from int* const p (const pointer). Read right-to-left.

Common Mistakes

const int* p vs int* const p: Order matters! const int* p = "pointer to const int", int* const p = "const pointer to int".

Const member functions limitations: const member functions can only call other const member functions on member objects.

Cannot pass const to non-const reference: Can't pass const objects to non-const reference parameters - the function might modify them.

Const only prevents modification through that variable: const int& ref{x}; x = 10; works - x itself is not const, only the reference.

Debug Challenge

This function should display a Player without modifying it. Click the highlighted line to fix the parameter:

1 #include <iostream>
2 #include <string>
3
4 class Player { public: std::string name; int health; };
5
6 void display(Player player) {
7 std::cout << player.name << ": " << player.health << "\n";
8 }

Quick Quiz

  1. What does const int* p mean?
Pointer to a constant int - value cannot be changed through pointer
Constant pointer to an int
Both pointer and int are constant
  1. Why use const references for function parameters?
They prevent copying and modification
They are faster than pointers
They allow null values
  1. Can you call a non-const member function on a const object?
No - only const member functions can be called
Yes - all member functions work
Only in main()

Practice Playground

Time to try out what you just learned! Play with the example code below, experiment by making changes and running the code to deepen your understanding.

Lesson Progress

  • Fix This Code
  • Quick Quiz
  • Practice Playground - run once