I am under the impression that it is a C++ class contained in a library written by a third party. I tried searching on Google, and I found one post that said it was a good idea to use it. However, it failed to describe exactly what it is and how I can incorporate it into my code. Thanks.
ScopeGuard
was once a particular implementation of scope guards by Petru Marginean and Andrei Alexandrescu. The idea is to let the destructor of a guard object call a user specified cleanup action at the end of a scope (read: block), unless the scope guard is dismissed. Marginean came up with an ingenious idea of declaring a scope guard object for C++03, based on lifetime extension of a reference to const
.
Today “scope guard” is more the general idea.
Scope guards are based on RAII (automatic destructor calls used for cleanup), just as e.g. a for
loop is based on jumps, but one wouldn't ordinarly call a for
loop a jump-based piece of code, because that loses most of the information of what it is about, and likewise one does not ordinarily refer to scope guards as RAII. for
loops are at a higher level of abstraction, and are a more specialized concept, than jumps. Scope guards are at a higher level of abstraction, and are a more specialized concept, than RAII.
In C++11 scope guards can be trivially implemented in terms of std::function
, with the cleanup action supplied in each place via a lambda expression.
Example:
#include <functional> // std::function
#include <utility> // std::move
namespace my {
using std::function;
using std::move;
class Non_copyable
{
private:
auto operator=( Non_copyable const& ) -> Non_copyable& = delete;
Non_copyable( Non_copyable const& ) = delete;
public:
auto operator=( Non_copyable&& ) -> Non_copyable& = default;
Non_copyable() = default;
Non_copyable( Non_copyable&& ) = default;
};
class Scope_guard
: public Non_copyable
{
private:
function<void()> cleanup_;
public:
friend
void dismiss( Scope_guard& g ) { g.cleanup_ = []{}; }
~Scope_guard() { cleanup_(); }
template< class Func >
Scope_guard( Func const& cleanup )
: cleanup_( cleanup )
{}
Scope_guard( Scope_guard&& other )
: cleanup_( move( other.cleanup_ ) )
{ dismiss( other ); }
};
} // namespace my
#include <iostream>
void foo() {}
auto main() -> int
{
using namespace std;
my::Scope_guard const final_action = []{ wclog << "Finished! (Exit from main.)\n"; };
wcout << "The answer is probably " << 6*7 << ".\n";
}
The rôle of the function
here is to avoid templating so that Scope_guard
instances can be declared as such, and passed around. An alternative, slightly more complex and with slightly constrained usage, but possibly marginally more efficient, is to have a class templated on a functor type, and use C++11 auto
for declarations, with the scope guard instance created by a factory function. Both these techniques are simple C++11 ways to do what Marginean did with reference lifetime extension for C++03.
It's more of a design pattern than a particular class. It is a way of aquiring/releasing resources (such as files, memory, or mutexes) that is exception safe. unique_lock
in c++11 follows this pattern.
For example, with unique_lock
, instead of writing code like this:
void foo()
{
myMutex.lock();
bar();
myMutex.unlock();
}
You write code like this:
void foo()
{
unique_lock<mutex> ulock(myMutex);
bar();
}
In the first case, what if bar
throws an exception? Then, myMutex
will never be unlocked, and your program would be left in an invalid state. In the second case, however, unique_lock
is programmed to lock the mutex in its constructor, and unlock it in its destructor. Even if bar
throws an exception, the unique_lock
will be destructed as the stack unwinds when the exception travels upward, and so the lock will be released. This saves you having to wrap every call to bar
in a try/catch block and handle exceptions manually.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With