3

通常需要完成以下任务:更改某物的状态,执行操作,然后将状态更改回原始状态。例如,在 Win32 GDI 中,需要更改背景颜色,然后进行一些绘图,然后将颜色更改回来。

它可以直接完成:

COLORREF oldColor = SetBkColor( deviceContext, newColor );
drawStuff( deviceContext );
SetBkColor( deviceContext, oldColor );

或者通过一个括号类,它将在构造函数中进行前向更改和在析构函数中进行后向更改:

CBkColorSwitcher switcher( deviceContext, newColor );
drawStuff( deviceContext );
//once control reaches end of block the switcher is destroyed and the change is reverted

括号类的优点是显而易见的——如果在更改之间引发异常,则更改将正确恢复。有什么缺点?

4

6 回答 6

12

这实际上是一个众所周知且广泛使用的 C++ 习语,称为RAII。Win32 API 是 C API,它们的实现模式不同。如果您使用 C++ 进行编程,最好使用 RAII 习惯用法来处理资源分配和释放,方法是在 C API 上编写瘦包装器,或者更好地重用现有的、设计良好的 C++ 替代品。Java 程序员可以将 RAII 视为finally子句的替代品。

于 2009-08-12T12:34:31.030 回答
4

有几个缺点,您需要编写更多代码,最终会创建更多对象。您无法控制它的使用。用错了,你就失去了好处。例如

CBkColorSwitcher * switcher = new CBkColorSwitcher(......)

也就是说,我认为优点远远大于缺点,并且更喜欢括号类方法

于 2009-08-12T12:34:50.997 回答
2

我认为这是一个最佳实践。我没有看到任何缺点(除了可读性?)

于 2009-08-12T12:33:29.873 回答
2

我看到的缺点是(至少在你给出的例子中):

  • 除非代码的读者理解括号类的职责,否则您实际上在做什么不太清楚。
  • 创建括号类的成本
  • 编写代码来实现括号类将比没有它的版本花费更长的时间。

话虽如此,使用 RAII 是做到这一点的“正确”方法,而且好处远大于坏处。

于 2009-08-12T12:38:34.603 回答
1

一个缺点是您通常实际上必须定义一个新类,这往往会产生一些开销。

除此之外,它是(另一个)非常常见的 RAII 示例,并且通常是一种非常好的方法。

编辑:如果不是编写一个只有一个函数的类,您可以使用shared_ptr它在退出范围时执行任意代码块。我认为这对于大多数应用程序来说可能有点太可爱了。

于 2009-08-12T12:34:43.790 回答
1

我在这里吹毛求疵,但是:

  1. 代码大小,由于异常处理程序,您的代码会更大。
  2. 您需要编写很多类来处理各种开关。
  3. 更大的堆栈。
  4. 始终在所有异常上执行代码,即使不需要(例如,您只想让应用程序崩溃)
于 2009-08-12T12:42:46.090 回答