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

时间:2011-11-08 08:35:22

标签: c++ concurrency

在C ++中使用Resource Acquisition Is Initialisation (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);
}

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

在调用doOneMoreThing()后,是否只在调用析构函数的析构函数时调用了预期行为?在C ++中定义良好的行为?

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

2 个答案:

答案 0 :(得分:7)

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

§12.4.11说:

  

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

§6.7.2说:

  

块中声明的具有自动存储持续时间的变量是   从街区退出时被摧毁(6.6)

和§6.6.2声明:

  

退出范围(无论多么已完成),具有自动对象   在该范围内构建的存储持续时间(3.7.3)   按照与其建造相反的顺序销毁。

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

答案 1 :(得分:3)

它在C ++中有很好的定义,这就是RAII工作的原因。所有自动对象在它们超出范围的位置被销毁,与构造的顺序相反。