That’s the normal behaviour, albeit probably unexpected!
You’re running into a hard boundary between OS-managed resources and external hardware state. A ctrl-c, such as early program termination or interrupting an Infinite loop frees the mcu resources from the linux core, whereas other exit methods do not.
As far as I could ever determine, dog.close() is not a cleanup method, it is a terminal control-flow primitive, it assumes it is called from top-level code and it was never meant to return.
So, in summary, what you see is normal. The other examples that run infinitely, will need ctrl-c to terminate anyway and this then automatically frees resources. They are absolutely fine.
I tried to explain the options a bit better here via 3 different worked example scenarios