You should basically never write code that requires you to write corresponding code later in the control flow.
The obvious examples are resource acquisition things like allocating memory (you have to free it later) or opening a file (you have to close it later), and there are lots of other examples provided around this question.
The problem is that when you do this, you make a hidden rule that, in order to maintain your code correctly, whenever you change the code in one place, you have to change the code in the other place in a corresponding way. In fact, all the code that might affect the opened/closed, allocated/free or whatever status needs to be maintained as a single unit, even though it could be spread out across the code base.
That is a recipe for bugs, and these bugs used to happen all the time.
Now, these kinds of bugs hardly ever happen, because professional C++ programmers always use use RAII to make sure there are no hidden correspondences like that.
If you acquire a resource or do something else that needs to be cleaned up later, then the code that does that should also ensure that it gets cleaned up automatically, at the appropriate time, as variables that refer to that resource go out of scope.
This is a very general rule. It doesn't make sense to ask for an exhaustive list of all the things that require RAII, because the list is endless, and programmers need to be able to create their own.
I use RAII when generating XML, for example, to ensure that if I write a start tag, then I will also write the corresponding end tag at some point. That sort of thing is not going to be on anybody's pre-written list of "RAII situations".
using
or similar, works. Things get complicated when resources need to escape function scope. That's one thing Rust ownership mechanics tries to (help to) solve, and you can see it's not trivial. $\endgroup$