When using Resource Acquisition Is Initialisation (RIAA) in C++ it’s typical to have something the following:
class CriticalSection {
public:
void enter();
void leave();
};
class SectionLocker {
public:
SectionLocker(CriticalSection& cs)
: mCs(cs) {
cs.enter();
}
~SectionLocker() {
cs.leave();
}
private:
CriticalSection& mCs;
};
CriticalSection gOperationLock; // Global lock for some shared resource
void doThings(int a, int b) {
SectionLocker locker(gOperationLock);
int c = doOtherThings(a);
doMoreThings(b);
doOneMoreThing(a, b, c);
}
I know that in some garbage collected languages (such as the CLR) that one of the many reasons why this would be unsafe is that the locker object inside doThings() would be eligible for garbage collection before doThings() returns, as locker is never referenced after being created.
Is the expected behaviour, of the destructor for locker only being called after the call to doOneMoreThing(), well defined behaviour in C++?
If so, are there any guarantees about when the destructor will be called (and gOperationLock is released)? Or is it just at some point after it goes out of scope?
The C++ standard (n3290) is pretty clear on this. Your RAII objects are always going to have automatic storage duration (if they don’t you’re doing it wrong!) so
§12.4.11 says:
§6.7.2 says:
and §6.6.2 states:
Which read together leaves no doubt that the only conforming way to implement this is for the observable behaviour to be that automatic storage objects are destructed at the end of a block.