* Ivan Novick:
I'll bite. Can you please explain what you have done with this code?
Especially the 3rd line in main?
Ah, yes. It wasn't meant as a mystery. The third line could have been
written as just
d[1] = d[0] + 1;
But in general, operator[] does no bounds checking, so if the indices
are out of bounds (i.e. negative or larger than the vector size) the
result is immediate C++ Undefined Behavior, which is difficult to detect
and debug because anything or nothing might happen.
'at' does bounds checking and throws an exception for out-of-bounds, and
is otherwise the same as operator[]; therefore recommended as default,
writing
d.at(1) = d.at(0) + 1;
unless profiling shows this to be a real bottlneck performancewise,
/and/ a reasonable proof that no out-of-bounds access happens, exists.
The immediate (possible) Undefined Behavior of operator[] is with 'at'
turned into a more well-behaved exception, which is more easily
detectable and easy to debug.
Since this program has no try-catch the formal C++ Undefined Behavior
again rears it ugly head (or would that be "behind"?) at a higher level
-- when the possible exception propagates out of 'main'.
Happily, on most C++ implementations an exception out of 'main' causes
well-defined /implementation defined/ behavior, which we usually call a
"crash"; again, easy to detect and debug. In practice it can be much
easier to detect and debug than if there is a try-catch in 'main'. On
the other hand, for a program distributed to end-users, the end-user
will not necessarily have a debugger or understand a core dump or
whatever a "crash" is on the end-user's machine, so for such a program
it should perhaps be written as
#include <cstddef> // EXIT_SUCCESS, EXIT_FAILURE
#include <stdexcept> // std::exception
...
int main()
{
using namespace std;
try
{
// Former contents of 'main', then
return EXIT_SUCCESS;
}
catch( std::exception const& x )
{
cerr << "!Sorry, I crashed (program failure)." << endl;
cerr << "!Technical info: " << x.what() << endl;
return EXIT_FAILURE;
}
}
And of course that construction can be written once and for all and
reused, just calling a 'cppMain' function (or whatever) from 'main'.