Const Correctness in C++
This is a note for Lecture 8, CS106L, Spring 2023.
INTRODUCTION
What's const?
Def.
const
: keyword indicating a variable, function or parameter can't be modified
const
variables can be references or not.
Ex.
1 | std::vector<int> vec{1, 2, 3}; |
Why const?
It helps find out mistakes.
1 | void f(const int x, const int y) { |
Since the variable y
is const, y=-1
can be found by the compiler.
CONST AND CLASSES
INTRODUCTION OF CONST-INTERFACE
Recall our Student
class:
1 | // student.h |
1 | // student.cpp |
What if we use a const Student
?
1 | // main.cpp |
It causes compile error! The compiler doesn't know getName
and getAge
don't modify s
! We need to promise that it doesn't by defining them as const functions, by adding const
to the end of function.
1 | // student.h |
1 | // student.cpp |
Def.
- const-interface: All member functions marked
const
in a class definition. Objects of typeconst ClassName
may ONLY use the const-interface.
PRACTICE
Let's make StrVector
's const-interface!
Questions to ask whether a function should be a const-interface:
- Should this function be able available to a const object?
1.1. Can I mark the function const as is (i.e. the function doesn't modify the object)?
1.2. Otherwise, can I make a const version of the function?
1 | class StrVector { |
size()
and empty()
should be const-interfaces. Of course. What about at()
? Seems like at
doesn't modify the vector... can we just mark at
const like we did with the other functions?
NO!
The problem is that at
returns a reference to an element in the vector. That element reference could be modified (thereby modifying the vector). For example:
1 | // StrVector my_vec = { "sarah", "haven" }; |
The solution should be adding a const version at
function.
1 | std::string& at(size_t indx); |
And implement them like this:
1 | std::string& StrVector::at(size_t index) { |
Learn more about static_cast
and const_cast
here
Should begin()
and end()
be const
?
Consider a function with const StrVector
param:
1 | void printVec(const StrVector& vec) { |
This code will compile! begin()
and end
don't explicitly change vec
, but they give us an iterator that can! But, we also need a way to iterate through a const vec
just to access it.
The solution is const_iterator
:
1 | class StrVector { |
CONST ITERATOR vs CONST_ITERATOR
This is tricky!
Iterator Type | Increment Iterator? | Change underlying value? |
---|---|---|
iterator | ✅ | ✅ |
const_iterator | ✅ | ❌ |
const iterator | ❌ | ✅ |
const const_iterator | ❌ | ❌ |
1 | using iterator = std::string*; |
RECAP
- Use const parameters and variables wherever you can in application code
- Every member function of a class that doesn't change it member variables should be marked
const
- Don't reinvent the wheel! Use our fancy
static_cast
/const_cast
trick to use the non-const version to implement a const version of a function auto
will drop allconst
and&
, so be sure to specify- Make iterators and const_iterators for all your classes!