From -fsanitize=address, this code wasn't calling the proper destructor.
Adding virtual destructors for each inherited class and the base class
fixes this bug.
While we are at it, mark the functions as final.
Now that clang-format makes [[nodiscard]] attributes format sensibly, we
can apply them to several functions within the common library to allow
the compiler to complain about any misuses of the functions.