Both are good approaches. If you are working on the logic of a simple NPC character, and have 2 states, Idle and OutOfScene. With a State Machine class that update a state enum, know the state of the character is too simple. And in the "Global Loop" of the character logic, your only task is checks the machine states. But if the character is a little more complex, for example, when we are close of them begins a animation. Now our logic have a new state called "speaking". So, It's very convenient listen when happens character change of state. So, If you store a function pointer to a function called "doSpeakAnimation", when the character change to the state "speaking", just call to "doSpeakAnimation" and your code will be more elegant.
My conclusion is that. The right approach depends of your necessity.