TE
科技回声
首页24小时热榜最新最佳问答展示工作
GitHubTwitter
首页

科技回声

基于 Next.js 构建的科技新闻平台,提供全球科技新闻和讨论内容。

GitHubTwitter

首页

首页最新最佳问答展示工作

资源链接

HackerNews API原版 HackerNewsNext.js

© 2025 科技回声. 版权所有。

C++11: Try/Catch/Finally Pattern Using RAII & Lambdas

32 点作者 code-dog大约 13 年前

3 条评论

ot大约 13 年前
What the OP describes here is a common C++ pattern known as "scope guard" (check "Solution 4" in <a href="http://drdobbs.com/184403758" rel="nofollow">http://drdobbs.com/184403758</a>). It was possible to implement it in C++03 with some tricks but C++11 lambdas make it much easier.<p>This is a very nice small implementation but, as always with C++, devil is in the details:<p>* Creation of an std::function needs a dynamic allocation, so if the allocation fails an exception will be thrown and if the <i>finally</i> is guarding a resource, the resource will be leaked<p>* std::function has a non-negligible calling overhead, hence this should not be used in performance-sensitive code<p>* Checking a condition inside the finally clause is not very elegant, a better idiom in C++ is to support <i>dismissing</i> a scope guard.<p>* The finallyClause may throw an exception, and since it is called in a destructor this is generally considered a bad idea. I don't know what could happen in this case, but some scope guard implementations I've seen catch the exception and explicitly call std::terminate(). I guess this is for performance reasons, because the destructor can be declared nothrow.<p>Here there is a more complex implementation, which addresses most of the corner cases:<p><a href="http://channel9.msdn.com/Shows/Going+Deep/C9-Lectures-Stephan-T-Lavavej-Advanced-STL-6-of-n#c634477472460000000" rel="nofollow">http://channel9.msdn.com/Shows/Going+Deep/C9-Lectures-Stepha...</a>
评论 #3693459 未加载
evincarofautumn大约 13 年前
I’ve done this before, and this version has a significant flaw: it is not exception-safe. The destructor should not read as it does:<p><pre><code> ~finally() { finallyClause(); } </code></pre> This allows exceptions thrown by finallyClause() to propagate out of the destructor, which, if an exception is already being thrown, will result in a call to std::terminate(), causing the application to die horrifically. Because C++ kinda-should’ve-but-really-doesn’t have checked exceptions, we must simply discard them:<p><pre><code> ~finally() { try { finallyClause(); } catch (...) {} } </code></pre> You can also avoid problems with exceptions and std::function’s dynamic allocation by using a template instead:<p><pre><code> template&#60;class F&#62; class finally_type { public: explicit finally_type(F f) : function(f) {} ~finally_type() { try { function(); } catch (...) {} } private: finally_type(const finally_type&#38;); finally_type&#38; operator=(const finally_type&#38;); F function; }; template&#60;class F&#62; finally_type&#60;F&#62; finally(F f) { return finally_type&#60;F&#62;(f); } </code></pre> This can be used like so:<p><pre><code> void test() { int* i = new int; auto cleanup = finally([i]() { delete i; }); may_throw(); } </code></pre> Finally (har!) the equivalent idiom in C++03:<p><pre><code> void test() { int* i = new int; struct finally { finally(int* i) : i(i) {} ~finally() { delete i; } int* i; } cleanup(i); may_throw(); }</code></pre>
评论 #3693718 未加载
评论 #3693467 未加载
NerdsCentral大约 13 年前
I was not expecting this to produce so much interest. I guess a lot of people have asked about how to implement try/catch/finally in C++.