Boost logo

Boost :

From: Andrey Semashev (andrey.semashev_at_[hidden])
Date: 2023-12-03 01:37:52


On 12/3/23 01:31, Andrzej Krzemienski wrote:
> sob., 2 gru 2023 o 22:20 Andrey Semashev via Boost
> <boost_at_[hidden] <mailto:boost_at_[hidden]>> napisał(a):
>
> On 12/2/23 23:12, Andrzej Krzemienski via Boost wrote:
> > Hi All,
> > Two observations from reading the docs.
> >
> > Why do I need a condition in scope_exit when I have a scope_fail?
>
> There is a discussion about this in this section:
>
> https://lastique.github.io/scope/libs/scope/doc/html/scope/scope_guards.html#scope.scope_guards.condition_functions <https://lastique.github.io/scope/libs/scope/doc/html/scope/scope_guards.html#scope.scope_guards.condition_functions>
>
> In short, scope_fail implies processing a failure event (for whatever
> definition of "failure") and scope_exit has no such connotation and can
> be used with arbitrary conditions. The different scope guards have
> different default conditions, too.
>
> Having read the linked section as well as your reply, I still do not
> understand the need for a scope_exit with a failure condition.
> I either want to *always* call the callback function on scope exit, or
> only under some condition. If it is under some condition, I would call
> scope_failure or scope_success respectively. 
>
> Or are you saying that sometimes I want to call or skip the call based
> on random conditions not having to do with failing anything, and where
> the set_active would not work? Is that it? Do you have any convincing
> examples for this?

I do not have a real life use case but I also don't think that every
condition must fall in the success/failure category. For example, you
could log the state of your program in certain conditions, which are not
necessarily a failure.

  class processor
  {
  private:
    std::queue<request> m_requests;
    bool m_interrupt;

  public:
    void enqueue_request(request const& req);

    void process_requests()
    {
      scope_exit logging_guard
      {
        [this]
        {
          // Log the state whether or not we're leaving
          // with an exception
          std::cout << m_requests.size()
            << " unprocessed requests left" << std::endl;
        },
        [this] { return !m_requests.empty(); }
      };

      while (!m_interrupt && !m_requests.empty())
      {
        BOOST_SCOPE_FINAL [this] { m_requests.pop(); };
        m_requests.front().process(); // may throw
      }
    }
  };

It is true that sometimes this can be achieved by using set_active() or
even merging the condition into the action, but there may be cases when
that is not convenient. Calling set_active needs to be done manually at
every return point, which is error-prone. Merging the condition into
action may be messy, especially if the condition is not so trivial and
needs to be used in multiple scope guards. You can move the condition
into a separate function object and reuse it with different actions.

In any case, the support for condition function objects is needed by the
library anyway, it's not like that functionality is unused. I don't see
the reason to actively hide it from users.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk