Skip to content

← Const Correctness and Class Design step 1 of 3

Easy Primitives

The accessor that will not let you look

Put const after a member function's parameter list to make it callable through a const object or reference:

int value() const;

Inside this function, this has type const Reading*. Access through it cannot modify ordinary, non-mutable data members. For the Reading class in this exercise, id() and value() only read members, so both can be const.

Why the caller fails to compile

const Reading& reading = readings[0];
int value = reading.value();

The call requires a const-qualified value() member. Without that qualifier, the compiler rejects the call even if the function's body only reads data. Adding const to the accessor fixes its interface; removing const from the caller would weaken the caller's intended read-only access.

A const member can also be called on a non-const Reading. The modifying scale member must remain non-const because it assigns to value_.

Const access is not deep immutability

A const member function can still change an object reached through a pointer:

class View {
    int* data_;
public:
    explicit View(int& value) : data_(&value) {}
    void write(int value) const { *data_ = value; }
};

write cannot reseat data_ through this const access path, but it can modify the pointed-to integer. The integer must still be alive and writable. Constness also does not prevent changes through another mutable reference, or side effects such as logging. A class's interface should make its intended read-only behaviour clear in addition to following the compiler's rules.

Mutable members

A member declared mutable may change even through a const object:

mutable int cached_total_ = 0;

A cache or a mutex can use this when changing its internal state does not change the logical value represented by the object. The compiler permits mutable writes; it does not verify that they preserve that logical value. Nor does mutable provide thread synchronization. Do not make this exercise's value_ mutable merely to allow scaling through const access.

Your task

The starter fails to compile because summarise reads through const Reading references, but the accessors lack const qualifiers. Add the appropriate qualifiers to Reading::id() and Reading::value(). Leave their bodies, the data members, scale, summarise and report unchanged.

report first multiplies every reading's value by factor. It then returns the reading's ID when the scaled value is at least threshold, or -1 otherwise, preserving input order. Empty input produces an empty result. Test products fit in int.

For readings [(1, 5), (2, 3)], factor 2 and threshold 10, the values become 10 and 6, so the result is [1, -1]. Equality with the threshold qualifies. The fix lets the existing read-only summarise function inspect the values after the modifying report step.