Most programs do not need to deal with memory exhaustion. There's often little that can be done other than terminating anyway, many OS configurations remove your ability to effectively recover from it (overcommit and swapping making your app unusably slow so you would better off terminating), and adding rarely tested code paths is a good way to introduce bugs and vulnerabilities.
Programs should abort when the disk fills up due to swap exhaustion, yes. They shouldn't abort if I/O fails, but that's because (a) I/O failure potential occurs in many fewer places than memory allocation failure potential, so it's easier to test; (b) I/O failure can occur for many reasons other than disk space exhaustion, and it's usually fine to handle disk space exhaustion the same way you handle other types of I/O failure, so it isn't any extra burden to handle that case.