Draft: Add experimental standard scope guards
This adds an implementation for scoped guards proposed for the standard library: https://en.cppreference.com/w/cpp/experimental/lib_extensions_3. We use guards in some places but they are very basic. It would be nice to have a proper solution, so this is to a proper implementation of the generic guard for the experimental std::scope_[exit|fail|success]
.
Merge request reports
Activity
added 48 commits
-
1af08520...e9c88282 - 46 commits from branch
master
- d0902925 - Add experimenta standard scope guards
- 105c69f8 - Simplify code
-
1af08520...e9c88282 - 46 commits from branch
Is there any interest on this utility? I find it very useful to properly handle code that must have scope handling. Notice that manual scope handling becomes particularly difficult when the code has branches or an exception occurs. There is at least one place where we would have immediate use for this:
Dune::BlockVector<T,A>::ScopeGuard<F>
.I have never used scope guards (explicitly) with cleanup functions and such. I need to see an application where it is needed to get an opinion about it.
That it is necessary to use something like scope guards to implement a simple block vector data-structure sounds a bit strange in my opinion. But I don't know the details and have not touched the implementation of this class, so cannot really judge.
That it is necessary to use something like scope guards to implement a simple block vector data-structure sounds a bit strange in my opinion.
The scope guard in block vector is needed because it has similar error handling guarantees as
std::vector
. If some of the non-const
functions throws, the dune vector still has a consistent state previous to the failure (e.g. ifresize
throws because allocation fails or because one of themove
d elements throws then the size is as before and the data is not moved or moved back to its original place). In theBlockVector
case, this guard makes sure that the dune vector is always is in sync withstd::vector
even if an exception is thrown. Doing this manually would require a lot oftry {} catch (...) {}
blocks.I have never used scope guards (explicitly) [...]
This is basically a convenience for having RAII on-the-fly (I just added an example in cppreference ;-)). Maybe this is not used a lot because the pattern is not known (e.g. gmsh reader). Consider the following case:
std::mutex mutex; { mutex.lock(); FILE* fp = std::fopen("/tmp/test.txt", "w+"); // do work (maybe throw) if (/* condition */) return; // do more work (maybe throw) std::fclose(fp); mutex.unlock(); } { auto guard = std::lock_guard{mutex}; FILE* fp = std::fopen("/tmp/test.txt", "w+"); // do work (maybe throw) if (/* condition */) return; // do more work (maybe throw) std::fclose(fp); } { auto guard = std::lock_guard{mutex}; FILE* fp = std::fopen("/tmp/test.txt", "w+"); auto guard = std::scope_exit{[fp]{ std::fclose(fp); }}; // do work (maybe throw) if (/* condition */) return; // do more work (maybe throw) }
Only the last one does proper lifetime management of the mutex and file handler due the RAII of the scope guards. One could of course move RAII to its own class, but some times that's unnecessary if there is an appropriate scope handling mechanism. In summary:
Utility Behavior scope_success{f}
Executes functor f()
on scope success (normal exit)scope_fail{f}
Executes functor f()
on scope failure (exception is thrown)scope_exit{f}
Executes functor f()
on scope success or failureGcc already has its own implementation. Compared to this one, they chose to implement each class separately which is definitely more readable. Unfortunately clang does not have any yet. So this implementation could be just a fallback. I made it before we had concepts support, so the constructors could certainly be simplified.
I wrote this before looking at gcc's to not worry about licensing. But if there is any issue with this one we could just pick up gcc's and handle the licensing. It's not very long and, to be fair, it's a bit more maintainable than mine.
added 120 commits
-
105c69f8...6c054a7b - 119 commits from branch
master
- 958f77d5 - Add experimental standard scope guards
-
105c69f8...6c054a7b - 119 commits from branch