Skip to content

Immutable Objects

An object whose state cannot be changed after it is created. Once created — locked forever.

Think: A birth certificate — once issued, the data never changes.

Why Immutable?

BenefitExplanation
Thread safeNo locks needed, can't be modified concurrently
PredictableState never changes unexpectedly
Safe sharingPass anywhere without fear of modification
Easy cachingSame input always gives same output

Basic Immutable Class

cpp
class Point {
private:
    const int x; // const member
    const int y; // const member
public:
    Point(int x, int y) : x(x), y(y) {} // must use initializer list for const
    int getX() const { return x; } // only getters — no setters
    int getY() const { return y; }
};

Point p(3, 4);
// p.x = 10;     // ERROR — const member
// p.setX(10);   // no such method

Immutable Class — Full Example with Money

cpp
class Money {
private:
    const double amount;
    const string currency;
public:
    Money(double a, string c) : amount(a), currency(c) {}
    double getAmount() const { return amount; }
    string getCurrency() const { return currency; }

    Money add(const Money& other) const { // returns NEW object
        if (currency != other.currency) throw "Currency mismatch!";
        return Money(amount + other.amount, currency);
    }

    Money multiply(double factor) const {
        return Money(amount * factor, currency); // returns NEW object
    }
};

Money m1(100.0, "USD");
Money m3 = m1.add(Money(50.0, "USD")); // new object — m1 unchanged!

Every operation returns a new object — original never changes.

const Keyword — Building Blocks

cpp
// const member variables — must use initializer list
class Config {
    const string host;
    const int port;
    const bool ssl;
    Config(string h, int p, bool s) : host(h), port(p), ssl(s) {}
};

// const methods — won't modify the object
double area() const { return 3.14 * radius * radius; }
double circumference() const { return 2 * 3.14 * radius; }

// const objects — can only call const methods
const Circle c(5.0);
c.area(); // OK — const method on const object
// c.setRadius(10); // ERROR

Immutable with Pointer Members

cpp
// pointer itself const but data isn't — NOT truly immutable
const int* data; // pointer const, value can change

// pointer AND data both const — truly immutable
const int* const data; // correct!

Builder Pattern for Immutable Objects

cpp
class Person {
private:
    const string name; const int age;
    const string email; const string phone;
    Person(string n, int a, string e, string p)
        : name(n), age(a), email(e), phone(p) {} // private constructor
public:
    class Builder {
        string name; int age=0; string email=""; string phone="";
    public:
        Builder(string n, int a) : name(n), age(a) {}
        Builder& setEmail(string e) { email = e; return *this; }
        Builder& setPhone(string p) { phone = p; return *this; }
        Person build() { return Person(name, age, email, phone); }
    };
    string getName() const { return name; }
};

Person p = Person::Builder("Alice", 25)
    .setEmail("alice@mail.com")
    .setPhone("9999999999")
    .build(); // immutable after this!

mutable Keyword — Exception to Immutability

cpp
class Cache {
private:
    mutable int accessCount = 0; // mutable — can change in const methods
    mutable bool cached = false;
    string data;
public:
    string getData() const {
        accessCount++; // OK — mutable
        if (!cached) { data = "loaded"; cached = true; }
        return data;
    }
};

mutable allows specific members to change even in const methods. Use for caching, logging, counters — not for actual object state.

Thread Safety with Immutable

cpp
// Mutable — needs locks
class MutableConfig {
    string host; mutex mtx;
    void setHost(string h) { lock_guard<mutex> lock(mtx); host = h; }
};

// Immutable — no locks needed!
class ImmutableConfig {
    const string host; const int port;
public:
    ImmutableConfig(string h, int p) : host(h), port(p) {}
    string getHost() const { return host; }
    // safe to share across threads — nothing to lock!
};

Summary Table

MutableImmutable
State after creationCan changeNever changes
SettersYesNo
Thread safeNeeds locksAlways safe
PredictabilityState can surpriseAlways consistent
New valuesModify in placeReturn new object
const membersOptionalAlways

Key Points

PointDetail
const membersMust use initializer list
No settersOnly getters allowed
New stateReturn new object
mutable keywordException for cache/logging
Builder patternBest way to construct complex immutable objects
Thread safetyAutomatic — no locks needed

One-liner: "An immutable object's state cannot change after creation — achieved via const members, no setters, and returning new objects for new states — making them inherently thread-safe and predictable."