const
correctness is the practice of designing code so that only code that needs to modify an instance is able to modify an instance (i.e. has write access), and conversely, that any code that doesn't need to modify an instance is unable to do so (i.e. only has read access). This prevents the instance from being modified unintentionally, making code less errorprone, and documents whether the code is intended to change the instance's state or not. It also allows instances to be treated as const
whenever they don't need to be modified, or defined as const
if they don't need to be changed after initialisation, without losing any functionality.
This is done by giving member functions const
CV-qualifiers, and by making pointer/reference parameters const
, except in the case that they need write access.
class ConstCorrectClass {
int x;
public:
int getX() const { return x; } // Function is const: Doesn't modify instance.
void setX(int i) { x = i; } // Not const: Modifies instance.
};
// Parameter is const: Doesn't modify parameter.
int const_correct_reader(const ConstCorrectClass& c) {
return c.getX();
}
// Parameter isn't const: Modifies parameter.
void const_correct_writer(ConstCorrectClass& c) {
c.setX(42);
}
const ConstCorrectClass invariant; // Instance is const: Can't be modified.
ConstCorrectClass variant; // Instance isn't const: Can be modified.
// ...
const_correct_reader(invariant); // Good. Calling non-modifying function on const instance.
const_correct_reader(variant); // Good. Calling non-modifying function on modifiable instance.
const_correct_writer(variant); // Good. Calling modifying function on modifiable instance.
const_correct_writer(invariant); // Error. Calling modifying function on const instance.
Due to the nature of const correctness, this starts with the class' member functions, and works its way outwards; if you try to call a non-const
member function from a const
instance, or from a non-const
instance being treated as const
, the compiler will give you an error about it losing cv-qualifiers.