Skip to content
Snippets Groups Projects

Draft: Add experimental standard scope guards

1 unresolved thread

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

Loading
Loading

Activity

Filter activity
  • Approvals
  • Assignees & reviewers
  • Comments (from bots)
  • Comments (from users)
  • Commits & branches
  • Edits
  • Labels
  • Lock status
  • Mentions
  • Merge request status
  • Tracking
  • added 48 commits

    Compare with previous version

    • 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. if resize throws because allocation fails or because one of the moved elements throws then the size is as before and the data is not moved or moved back to its original place). In the BlockVector case, this guard makes sure that the dune vector is always is in sync with std::vector even if an exception is thrown. Doing this manually would require a lot of try {} 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 failure
    • Scope guards can occasionally be very helpful in algorithms with many branches and exit points to make the semantics more clear and I've used them in a few places downstream. Hence it would be nice having them centrally in dune-common. I did not look at your particular implementation, though.

    • Gcc 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.

    • Please register or sign in to reply
  • added 120 commits

    Compare with previous version

  • added 1 commit

    • f3214e24 - Add experimental standard scope guards

    Compare with previous version

  • added 1 commit

    Compare with previous version

  • added 1 commit

    Compare with previous version

Please register or sign in to reply
Loading