基于堆栈的RAII是否只能在超出C++范围后才能运行?

Fre*_*est 3 c++ concurrency

在C++中使用资源获取初始化(RIAA)时,通常会有以下内容:

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);
}
Run Code Online (Sandbox Code Playgroud)

我知道在一些垃圾收集语言(例如CLR)中,为什么这不安全的众多原因之一是doThings()内的locker对象在doThings()返回之前有资格进行垃圾收集,因为locker永远不会创建后引用.

只有在调用doOneMoreThing()之后才调用析构函数的析构函数,这是C++中明确定义的行为吗?

如果是这样,是否有任何关于何时调用析构函数(并释放gOperationLock)的保证?或者仅仅是在它超出范围之后的某个时刻?

Fle*_*exo 7

C++标准(n3290)非常清楚.你的RAII对象总是会有自动存储持续时间(如果它们不是你做错了!)所以

§12.4.11说:

"当创建对象的块退出时,对于具有自动存储持续时间(3.7.3)的构造对象,隐式调用析构函数(6.7)"

§6.7.2说:

块中声明的具有自动存储持续时间的变量在块退出时被销毁(6.6)

和§6.6.2规定:

在从范围退出(但是已完成)时,在该范围内构造的具有自动存储持续时间(3.7.3)的对象将按其构造的相反顺序销毁.

一起阅读,毫无疑问,实现这一点的唯一符合方式是可观察的行为是在块的末尾破坏自动存储对象.