Explicit memory management requires programmers to manually free or delete the dynamically allocated memory. Languages, like C/C++, offer almost complete control (even address alignment at times) over the object’s lifecycle. For large systems, it requires strict programming discipline to ensure the long-term correctness and reliability of the programs. Some common coding pitfalls include:
- Dangling pointers due to releasing a live object
- Memory corruption due to double free
- Memory leaks due to forgetting to release memory
- Higher coupling between components due to modeling of ownership semantics in API signatures
There are many established patterns to avoid these pitfalls, but pretty much everything boils down to maintaining strict coding discipline that requires consistently using the correct memory management strategy. This becomes tricky for large programs where third-party dependencies or libraries might force a mix of multiple approaches. Memory issues are arguably among the hardest class of bugs to investigate.
For example, in case of dangling pointers or double free, the best outcome is the immediate crash of the program but typically it doesn’t happen and the program continues to run exhibiting unpredictable behavior. Hence the saying, to err is human — to blame it on a computer is even more so.
In this day and age, the biggest problem with the option of explicit memory management is that it exists.