Consider this code:
int func()
{
m_active_sessions_guard.lock();
... some code ...
if (x > y)
{
return -1;
}
... some more code ...
m_active_sessions_guard.unlock();
return 1;
}
We "forgot" the unlock
in the early return when x > y
is true. This could deadlock our program, or (worse!) cause the program to run slowly/misbehave in some other way.
By using a type that automatically unlocks the lock when the destructor is called, you are guaranteed that you don't "forget" to unlock the lock, EVER. I have certainly spent MANY hours looking for such problems, and I wouldn't wish it upon anyone - especially the ones where triggering the situation where it locks up or runs slow is only happening once in a while, so to even "catch" the failure you have to be lucky (maybe x > y
only happens on Thursdays, in months without "r" and when the date is divisible by both 7 and 3. So if you are unlucky enough to get the bug report at the end of April, you'll be debugging for a while... :)
The basis is RAII ("Resource Allocation Is Initialization"), and it's the same logic as why you want to use std::vector
rather than pointers and call new
/delete
yourself. Any time you can make the compiler do the job for you, you have a great benefit of "not having to remember". Computers programs, such as compilers, are very good at "remembering" things.