Bjarne Stroustrup在他的C++ Style and Technique FAQ中写道,强调我的:
因为C++支持几乎总是更好的替代方案:"资源获取是初始化"技术(TC++ PL3第14.4节).基本思想是通过本地对象表示资源,以便本地对象的析构函数将释放资源.这样,程序员就不会忘记释放资源.例如:
class File_handle { FILE* p; public: File_handle(const char* n, const char* a) { p = fopen(n,a); if (p==0) throw Open_error(errno); } File_handle(FILE* pp) { p = pp; if (p==0) throw Open_error(errno); } ~File_handle() { fclose(p); } operator FILE*() { return p; } // ... }; void f(const char* fn) { File_handle f(fn,"rw"); // open fn for reading and writing // use file through f }在系统中,我们需要为每个资源提供"资源句柄"类.但是,我们不必为每次获取资源都有一个"finally"子句.在现实系统中,资源获取比资源种类多得多,因此"资源获取是初始化"技术导致的代码少于使用"最终"构造的代码.
请注意,Bjarne写的"几乎总是更好"而不是"总是更好".现在我的问题是:finally
构造比在C++中使用替代构造(RAII)更好吗?
它们之间的区别在于析构函数强调通过将清理解决方案与正在使用的类型相关联来重用清理解决方案,而try/finally则强调一次性清理例程.因此,当您具有与使用点相关联的唯一一次性清理要求时,尝试/最终会更方便,而不是可以与您正在使用的类型相关联的可重用清理解决方案.
我没有尝试过这个(几个月没有下载最近的gcc),但它应该是真的:通过在语言中添加lambdas,C++现在可以finally
通过编写一个名为的函数来获得有效的等价物try_finally
.明显用法:
try_finally([] { // attempt to do things in here, perhaps throwing... }, [] { // this always runs, even if the above block throws... }
当然,你必须写finally
一次try_ ,但只有一次,然后你就可以了.Lambdas启用新的控制结构.
就像是:
templatevoid try_finally(const TTry &tr, const TFinally &fi) { try { tr(); } catch (...) { fi(); throw; } fi(); }
并且在GC的存在与try/finally而不是析构函数的偏好之间根本没有链接.C++/CLI具有析构函数和GC.他们是正交选择.尝试/最终和析构函数是针对不可替换资源所需的同一问题的两种确定性问题的略有不同的解决方案.
C++函数对象强调可重用性,但使一次性匿名函数变得痛苦.通过添加lambdas,匿名代码块现在很容易实现,这避免了C++传统上强调通过命名类型表达的"强制可重用性".
最后用C代码连接会更好.在RAII中包装现有的C功能可能会很痛苦.
我能想到最终块会"更好"的唯一原因是它需要更少的代码来完成同样的事情.例如,如果您有一个资源,由于某种原因不使用RIIA,您可能需要编写一个类来包装资源并在析构函数中释放它,或者使用finally块(如果它存在).
相比:
class RAII_Wrapper { Resource *resource; public: RAII_Wrapper() : resource(aquire_resource()) {} ~RAII_Wrapper() { free_resource(resource); delete resource; } Resource *getResource() const { return resource; } }; void Process() { RAII_Resource wrapper; do_something(wrapper.resource); }
与:
void Process() { try { Resource *resource = aquire_resource(); do_something(resource); } finally { free_resource(resource); delete resource; } }
大多数人(包括我)仍然认为第一个版本更好,因为它不会强迫你使用try ... finally块.您还只需要编写一次类,而不是在使用该资源的每个函数中复制代码.
编辑:像提到的litb一样,你应该使用auto_ptr而不是手动删除指针,这将简化这两种情况.