Or simply ask ChatGPT...
Roadmap:
- cover below topics shortly for now, then go deeper into each as time permits
- clarify undefined behavior
- how to avoid undefined behavior
- segmentation fault
- how to avoid seg fault
- other fancy words?
- minimum compilation
make
andcmake
for both gcc and clang - I heard pointers are scary (how to go about them)
- I heard memory management is scary (how to go about it)
- object lifetime, copy, move semantics
- ...
- table of contents
While catchy title this document is to solidify my knowledge of C++ peculiarities and document common issues.
I work on providing correct information but I'm not a C++ expert. Use at your own risk :)
Most widely used are GCC, Clang and MSVC.
TODO
cppreference.com is highly recommended. Other notable resources are:
- C++ Core Guidelines - actual best practices
- ISO standard - I recommend checking out Get Started, Tour and FAQ
- cplusplus.com - another website with reference and tutorials
How come a language can have an undefined behavior (let's shorten to UB)?
C++ has an ISO standard which defines types of compiler freedom. One of the types is called "undefined behavior" where compiler is given freedom to decide how to behave.
Why does it exist then? It allows compiler to perform optimizations.
UB should be avoided since the code may produce unexpected results and may (may not!) fail at run-time (not compile-time!). For this reason, Clang provides UndefinedBehaviorSanitizer and gcc has -fsanitize=undefined(?).
Examples of undefined behavior:
- Simple (expected) cases:
NULL
ornullptr
pointer dereference, or accessing pointer after callingdelete
orfree
- Division by zero, or INT32_MIN divided by -1 (see signed integer overflow)
- since INT32_MAX is 2147483647 and INT32_MIN is -2147483648 so division by -1 will result in overflow
- Accessing array or memory out of bounds
- More nuanced cases:
- Use of an uninitialized variables. Very common. Yes, in C++ you should initialize variables.
- Signed integer overflow is UB. Unsigned integer is defined to wrap around.
- Modifying same variable more than once in an expression
"Be very careful, use good tools, and hope for the best." John Regehr
- One approach is to define -Wall -Werr flags for gcc?
For now just copied exceprt from Regehr's article but would like to specify concrete steps:
- Enable and heed compiler warnings, preferably using multiple compilers
- Use static analyzers (like Clang’s, Coverity, etc.) to get even more warnings
- Use compiler-supported dynamic checks; for example, gcc’s -ftrapv flag generates code to trap signed integer overflows
- Use tools like Valgrind to get additional dynamic checks
- When functions are “type 2” as categorized above, document their preconditions and postconditions
- Use assertions to verify that functions’ preconditions are postconditions actually hold
- Particularly in C++, use high-quality data structure libraries
to be continued...