Menu
Coddy logo textTech

Mutable Keyword

Part of the Object Oriented Programming section of Coddy's C++ journey — lesson 30 of 104.

You've learned that const member functions cannot modify any member variables. But sometimes you need to change a member that doesn't affect the object's logical state - like a cache or an access counter. The mutable keyword provides an exception to the const restriction.

A mutable member can be modified even inside a const member function:

class DataFetcher {
    std::string data;
    mutable int accessCount;    // Can be modified in const functions
    
public:
    DataFetcher(std::string d) : data(d), accessCount(0) {}
    
    std::string getData() const {
        accessCount++;          // Allowed because accessCount is mutable
        return data;
    }
    
    int getAccessCount() const {
        return accessCount;
    }
};

Without mutable, incrementing accessCount inside the const function getData() would cause a compiler error. The mutable keyword tells the compiler: "This member is allowed to change even when the object is considered const."

Common use cases for mutable include caching computed values, tracking access statistics, and synchronization primitives like mutexes. In each case, the modification doesn't change what the object logically represents - a cached value is just an optimization, and an access counter is metadata about usage.

class Circle {
    double radius;
    mutable double cachedArea;
    mutable bool areaCached;
    
public:
    double getArea() const {
        if (!areaCached) {
            cachedArea = 3.14159 * radius * radius;
            areaCached = true;
        }
        return cachedArea;
    }
};

Use mutable sparingly - it should only be applied to members that don't affect the object's observable state.

challenge icon

Challenge

Easy

Let's build a document viewer that tracks how many times a document has been viewed — without breaking the const-correctness of our read-only methods. This is a perfect use case for the mutable keyword.

You'll create two files to organize your code:

  • Document.h: Define a Document class that stores content and secretly tracks view statistics. Your class needs:
    • Private members: title (string), content (string), and a mutable int viewCount that can be modified even in const methods
    • A constructor that takes a title and content, initializing viewCount to 0
    • A getTitle() const method that returns the title
    • A getContent() const method that increments viewCount (allowed because it's mutable) and returns the content
    • A getViewCount() const method that returns how many times the content has been accessed
    • A getPreview() const method that returns the first 20 characters of the content followed by "..." — this should NOT increment the view count since it's just a preview
  • main.cpp: Demonstrate how mutable allows tracking access statistics while keeping methods logically const. Read a document title and content from input (each on a separate line), then:
    • Create a Document with the input values
    • Print "Title: <title>"
    • Print "Preview: <preview>"
    • Print "Views after preview: <count>"
    • Access the full content using getContent() and print "Content: <content>"
    • Print "Views after first read: <count>"
    • Access the content again and print "Content: <content>"
    • Print "Views after second read: <count>"
    • Create a helper function void displayDocument(const Document& doc) that prints "[Const Access] <title>: <content>" — this proves our const methods work with const references
    • Call displayDocument() with your document
    • Print "Final view count: <count>"

The view count should be 0 after the preview (since previews don't count as full views), then increment each time getContent() is called. The mutable keyword makes this possible — without it, you couldn't modify viewCount inside const methods like getContent().

If the content is shorter than 20 characters, getPreview() should return the entire content followed by "...".

Cheat sheet

The mutable keyword allows a member variable to be modified even inside const member functions:

class DataFetcher {
    std::string data;
    mutable int accessCount;    // Can be modified in const functions
    
public:
    DataFetcher(std::string d) : data(d), accessCount(0) {}
    
    std::string getData() const {
        accessCount++;          // Allowed because accessCount is mutable
        return data;
    }
    
    int getAccessCount() const {
        return accessCount;
    }
};

Without mutable, modifying a member variable inside a const function would cause a compiler error. The keyword tells the compiler that this member is allowed to change even when the object is considered const.

Common use cases include caching computed values, tracking access statistics, and synchronization primitives. The modification should not change what the object logically represents:

class Circle {
    double radius;
    mutable double cachedArea;
    mutable bool areaCached;
    
public:
    double getArea() const {
        if (!areaCached) {
            cachedArea = 3.14159 * radius * radius;
            areaCached = true;
        }
        return cachedArea;
    }
};

Use mutable sparingly - only for members that don't affect the object's observable state.

Try it yourself

#include <iostream>
#include <string>
#include "Document.h"
using namespace std;

// TODO: Implement the displayDocument function
// It should print: "[Const Access] <title>: <content>"
void displayDocument(const Document& doc) {
    // TODO: Implement this function
}

int main() {
    // Read input
    string title;
    string content;
    getline(cin, title);
    getline(cin, content);
    
    // TODO: Create a Document with the input values
    
    // TODO: Print "Title: <title>"
    
    // TODO: Print "Preview: <preview>"
    
    // TODO: Print "Views after preview: <count>"
    
    // TODO: Access full content and print "Content: <content>"
    
    // TODO: Print "Views after first read: <count>"
    
    // TODO: Access content again and print "Content: <content>"
    
    // TODO: Print "Views after second read: <count>"
    
    // TODO: Call displayDocument() with your document
    
    // TODO: Print "Final view count: <count>"
    
    return 0;
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming