ScopeGuard的使用是否真的可以带来更好的代码?
我碰到了多年前由Andrei Alexandrescu和Petru Marginean撰写的这篇文章,其中介绍并讨论了一个名为ScopeGuard的实用程序类,用于编写异常安全代码。我想知道使用这些对象进行编码是否确实可以带来更好的代码,或者它混淆了错误处理,因此,在catch块中更好地呈现后卫的回调?有没有人在实际生产代码中使用这些工具有任何经验?
解决方案
回答
它肯定会改善代码。我们初步提出的说法是,它晦涩难懂,而代码将从" catch"块中获取,这在C ++中根本不成立,因为RAII是既定的习惯用法。 C ++中的资源处理是通过资源获取来完成的,而垃圾回收是通过隐式析构函数的调用来完成的。
另一方面,显式的catch
块会膨胀代码并引入细微的错误,因为代码流变得更加复杂,并且必须显式地进行资源处理。
RAII(包括ScopeGuard)在C ++中并不是一种晦涩的技术,但却是公认的最佳实践。
回答
我没有使用过这个特定的模板,但是之前我使用过类似的东西。是的,与以不同方式实现的同样健壮的代码相比,它的确可以使代码更清晰。
回答
我经常用它来保护内存使用,这些是需要释放的东西,它们是从OS返回的。例如:
DATA_BLOB blobIn, blobOut; blobIn.pbData=const_cast<BYTE*>(data); blobIn.cbData=length; CryptUnprotectData(&blobIn, NULL, NULL, NULL, NULL, CRYPTPROTECT_UI_FORBIDDEN, &blobOut); Guard guardBlob=guardFn(::LocalFree, blobOut.pbData); // do stuff with blobOut.pbData
回答
是的。
如果只有一条C ++代码可以建议每个C ++程序员花10分钟来学习,那就是ScopeGuard(现在是可免费使用的Loki库的一部分)。
我决定尝试将ScopeGuard(稍作修改)版本用于我正在开发的小型Win32 GUI程序。如我们所知,Win32具有许多不同类型的资源,需要以不同的方式关闭(例如,内核句柄通常使用CloseHandle()关闭,GDI BeginPaint()需要与EndPaint()配对,等。)我将ScopeGuard与所有这些资源一起使用,并用于分配带有" new"的工作缓冲区(例如,用于从Unicode到Unicode的字符集转换)。
令我惊讶的是程序缩短了多少。基本上,这是双赢的:代码同时变得更短,更健壮。将来的代码更改不会泄漏任何内容。他们只是做不到。多么酷啊?