何时不使用RAII进行资源管理

时间:2010-07-21 09:48:21

标签: c++ raii resource-management

任何人都可以向我提供一个或多个具体示例,其中RAII 是最有效的资源管理方法,为什么?

5 个答案:

答案 0 :(得分:2)

我能想到RAII不是解决方案的唯一情况是使用多线程关键区域锁定管理。通常,建议获取关键区域锁定(考虑资源)并将其保存在RAII对象中:

void push( Element e ) {
   lock l(queue_mutex);  // acquire on constructing, release on destructing
   queue.push(e);
}

但有些情况下您不能将RAII用于此目的。特别是,如果循环条件中使用的变量由多个线程共享,并且您无法保持整个循环执行的锁定,那么您必须使用不同的机制获取和释放锁定:

void stop_thread() {
   lock l(control_mutex);
   exit = true;
}
void run() {
   control_mutex.acquire();
   while ( !exit ) { // exit is a boolean modified somewhere else
      control_mutex.release();
      // do work
      control_mutex.acquire();
   }
   control_mutex.release();
}

现在甚至可以通过(ab)使用operator,来使用RAII,但我从未想过它。但我想这不是很自然:

void run() {
   while ( lock(control_mutex), !exit ) {
      // do work
   }
}

所以我猜答案不是我能想象的......

编辑:使用RAII解决同一问题的其他解决方案:

@ Mark Ransom

bool should_exit() const {
   lock l(mutex);
   return exit;
}
void run() {
   while ( !should_exit() ) {
      // do work
   }
}

@ fnieto

void run() {
   while (true) {
      {  lock l(mutex);
         if (exit) break;
      }
      // do work
   }
}

答案 1 :(得分:1)

有时需要两阶段初始化(创建,然后初始化,然后使用)。

甚至是三阶段:在我们的产品中,有一组独立的对象,每个对象都运行一个线程,并且能够通过优先级继承队列订阅任意数量的其他对象(包括它自己)。在启动时从配置文件中读取对象及其订阅。在构造时,每个对象都可以使用RAII(文件,套接字等),但是没有对象可以订阅其他对象,因为它们是按未知顺序构造的。因此,在构建所有对象之后,第二阶段将建立所有连接,第三阶段是,一旦建立所有连接,线程就会被释放并开始发送消息。同样,关闭也是多阶段的。

答案 2 :(得分:0)

GC可以为程序员处理循环数据结构的内存,而RAII则需要程序员在某处手动打破循环。

答案 3 :(得分:0)

RAII意味着资源的所有权是通过语言结构提供的保证来定义和管理的,最明显的是,但不限于构造函数和析构函数。

C ++中RAII的要点是资源所有权政策实际上可以通过语言强制执行。对RAII的一个较小的替代方案是让API 建议调用者(例如,通过注释或其他文档)在特定时间明确执行ACQUIRE()RELEASE()操作。这种政策不能用语言强制执行。

因此,最初的问题是另一种询问是否存在无法执行的资源管理方法优于RAII的情况。 我能想到的唯一案例是您故意绕开语言中现有的资源管理结构,并编写自己的框架。例如,您正在实现垃圾收集脚本语言解释器。原子的“虚拟分配”可能会玩内存块游戏。类似地,基于池的分配器期望程序最终调用DESTROY_POOL()操作,具有全局结果(即,从该池分配的任何项目将被无效)。

答案 4 :(得分:0)

在资源释放可能失败的情况下,RAII可能不足以管理该资源(因为析构函数不应该抛出)。 RAII可能仍然是该解决方案的一部分。