I would like to write a C#-like C++ event class like this :
template< typename ListenerType >
class Event
{
private:
std::vector< ListenerType * > m_aListeners;
public:
void operator += ( ListenerType * pListener )
{
m_aListeners.push_back( pListener );
}
void operator -= ( ListenerType * pListener )
{
std::vector< ListenerType * >::reverse_iterator revIter = m_aListeners.rbegin();
for( ; revIter != m_aListeners.rend(); ++revIter )
if( revIter == pListener )
{
m_aListeners.remove( revIter );
break;
}
}
};
class DataReceivedEvent : public Event< DataReceivedListener >
{
public:
void Trigger( const byte_t * pData )
{
for( size_t nI = 0; nI < m_aListeners.size(); ++nI )
m_aListeners[ nI ]->OnDataReceived( pData );
}
}
The problem is that it forces me to write a Trigger method that always does the same thing (iterate and call handlers) for each event type since different events can have a different list of parameter, and for each event, the associated handler type has a mehod with a specific name.
I don't know much about C++11, but i have the feeling that it would be possible to avoid rewritting the Trigger method for each event type using templates.
But i can't use C++11, so i wonder if there is a way, using older C++ version, to do that, in a type safe way.
EDIT : I thought about creating a hierarchy of event data classes, i.e template< typename ListenerType >::Data and DataReceivedEvent::Data : public template< typename ListenerType >::Data so that i can have a Trigger method always taking a single argument, i.e virtual void Trigger( const Data * pData ). But I still have the problem that it needs to call a specific method in the event listener.
You can use templates and operator overloading for this as well. When you assume that the ListenerType implements the operator() you can implement it like this (the example also uses variadic templates. You can use arbitrary amount of arguments):
#include <vector>
#include <iostream>
template< typename ListenerType >
class Event
{
private:
std::vector< ListenerType * > m_aListeners;
public:
void operator += ( ListenerType * pListener )
{
m_aListeners.push_back( pListener );
}
void operator -= ( ListenerType * pListener )
{
auto revIter = m_aListeners.rbegin();
for( ; revIter != m_aListeners.rend(); ++revIter )
if( revIter == pListener )
{
m_aListeners.remove( revIter );
break;
}
}
template<typename... Params>
void operator()(Params... data) {
for (auto l : m_aListeners) {
(*l)(data...);
}
}
};
class DataReceivedListener {
public:
void operator()(const char* pData) {
std::cout << pData << std::endl;
}
};
class DataReceivedEvent : public Event< DataReceivedListener >
{
public:
};
int main() {
DataReceivedEvent e;
DataReceivedListener l1;
DataReceivedListener l2;
e += &l1;
e += &l2;
e("Hello");
}
Unfortunately, C++11 does not introduces Concepts. If you had this (constraints in C#) you would get some more help by the compiler.
Here is the code I have...
struct Test {
string foo() { return "bar"; }
};
#define callFn(obj,method) obj->method();
int main() {
Test* t = new Test();
cout << callFn(t,foo); // bar
return 0;
}
...and here is the code I'd like to have
int main() {
Test* t = new Test();
string method = "foo";
cout << callFn(t,method); // bar
return 0;
}
Is it possible?
You can't. C++ doesn't have reflection capabilities.
You would have to define e.g. a std::map that maps strings to function pointers.
void foo(int x) { std::cout << "foo " << (x+3) << "\n"; }
void bar(int x) { std::cout << "bar " << (x+5) << "\n"; }
int main() {
std::map<std::string, void (*)(int)> mapper;
mapper["foo"] = &foo;
mapper["bar"] = &bar;
// ...
mapper["foo"](42);
mapper["bar"](42);
}
You probably want something like member function pointers:
typedef std::string (Test::*ptmf)();
#define CALL_MF(pobject, p) (((pobject)->*(p))())
int main()
{
ptmf method = &Test::foo;
Test * t = new Test;
std::string result = CALL_MF(t, method); // or directly: (t->*method)()
}
You can create containers whose elements are of type ptmf to manage different member function pointers at runtime:
std::map<int, ptmf> function_registry;
std::string call(int key, Test * t)
{
auto it = function_registry.find(key);
return (it != function_registry.end()) ? CALL_MF(t, *it) : "[ERROR]";
}
You can do something like this, but because C++ lacks reflection capabilities you have to do some extra work to make it possible.
struct base {
virtual void call_method( std::string const & ) = 0;
};
struct derived : public base {
std::string foo( ) const {
return "bar";
}
// More methods.
void call_method( std::string const &p_name ) {
if( p_name == "foo" ) {
this -> foo( );
}
// More checks on method names.
else {
// Handle invalid function name.
}
}
};
This is called a data-driven interface, where you pass commands to objects and they respond to the commands that they recognize in a polymorphic fashion. You can improve on what I showed by creating a statically initialized unordered map from commands to function pointer and then using that to resolve which function to call. It's good to avoid this type of function dispatch if you can, though, because it's slow in comparison to static function dispatch and error prone since typos may result incorrect calls or errors. It also has the downside that you can't get the return value easily, though it is possible in some cases.
EDIT: I wanted to give a more complete example of how this can be done, so here goes:
#include <cassert>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/blank.hpp>
#include <boost/variant.hpp>
#include <boost/function.hpp>
#include <boost/unordered_map.hpp>
#include <boost/assign/list_of.hpp>
// A base class that defines an interface to call methods by name
// and to access the list of methods. We use a map of argument
// names to boost::variants to pass arguments to the functions.
// Right now we support only ints and strings, but we can expand
// this to other types if we want. In particular, we can use
// boost::any to support arbitrary types, but it will be slow.
// Maybe that's not a big deal since function dispatch through
// named functions is slow anyway.
struct base {
typedef boost::variant< boost::blank, int, std::string > argument_t;
typedef boost::variant< boost::blank, int, std::string > return_t;
typedef boost::unordered_map< std::string, argument_t > param_map_t;
typedef boost::function< return_t ( base *, param_map_t const & ) >
method_t;
typedef boost::unordered_map< std::string, method_t > method_map_t;
return_t call_method(
std::string const &p_method
, param_map_t const &p_params = param_map_t( )
)
{
method_map_t::const_iterator l_itr =
get_methods( ).find( p_method );
if( l_itr == get_methods( ).end( )) {
// Handle undefined method identifier.
}
return l_itr -> second( this, p_params );
}
virtual method_map_t const &get_methods( ) const = 0;
};
// A trampoline object to elide the concrete type that
// implements the base interface and to provide appropriate
// casting. This is necessary to force all functions in our
// method map to have the same type.
template< typename U >
base::return_t trampoline(
base::return_t (U::*p_fun)( base::param_map_t const & )
, base *p_obj
, base::param_map_t const &p_param_map
)
{
U *l_obj = static_cast< U* >( p_obj );
return (l_obj ->* p_fun)( p_param_map );
}
// A derived type that implements the base interface and
// provides a couple functions that we can call by name.
struct derived : public base {
static method_map_t const c_method_map;
return_t foo( param_map_t const &p_params ) {
std::cout << "foo" << std::endl; return 1;
}
return_t bar( param_map_t const &p_params ) {
std::cout << "bar" << std::endl; return std::string( "bar" );
}
method_map_t const &get_methods( ) const {
return c_method_map;
}
};
// Construct map of method names to method pointers for derived.
base::method_map_t const derived::c_method_map = boost::assign::map_list_of
( "foo", boost::bind( &trampoline< derived >, &derived::foo, _1, _2 ))
( "bar", boost::bind( &trampoline< derived >, &derived::bar, _1, _2 ))
;
int main( ) {
base *blah = new derived( );
// Call methods by name and extract return values.
assert( boost::get< int >( blah -> call_method( "foo" )) == 1 );
assert( boost::get< std::string >( blah -> call_method( "bar" )) == "bar" );
// Iterate over available methods
typedef base::method_map_t::const_iterator iterator;
iterator l_itr = blah -> get_methods( ).begin( );
iterator l_end = blah -> get_methods( ).end ( );
for( ; l_itr != l_end; ++l_itr ) {
if( l_itr -> first == "foo" ) l_itr -> second( blah, base::param_map_t( ));
}
}
The output is:
foo
bar
foo
As you can see it's quite a bit of work to set this up, but adding new types that implement the interface is pretty easy.
This is essentially the reflection mechanism that's available in post Java1.5
Here's an example of reflections in C++
http://www.garret.ru/cppreflection/docs/reflect.html
Is there any non-awful way to have a collection of objects of more than one type? I'm perfectly happy to derive each type from a common base. I need sensible semantics so the collection can be copied, assigned, and so on.
Obviously, I can't just use a vector or list of the base class. Objects will be sliced and copying won't work at all. Using vectors or lists of pointers or smart pointers works, but you don't get sane copy semantics.
To get sane copy semantics, you need to use something like Boost's ptr_vector. But this requires a painful and error-prone infrastructure. Essentially, you can't just derive a new class from the base class because if it ever goes into the collection, it will not be properly copied.
This seems like such a common thing to do and all the solutions I know of are so awful. It seems like C++ is fundamentally missing a way to create a new instance of an object identical to a given instance -- even if that type has a copy constructor. And making a clone or duplicate function requires careful overloading in every derived class. If you fail to do it when creating a new class derived from the base (or any other class derived from that base) -- boom, your collection breaks.
Is there really no better way?
You can use std::vector<boost::any> to do most of this I think.
#include "boost/any.hpp"
#include <vector>
#include <iostream>
//Simple class so we can see what's going on
class MM {
public:
MM() { std::cout<<"Create # "<<this<<std::endl; }
MM( const MM & o ) { std::cout<<"Copy "<<&o << " -> "<<this<<std::endl; }
~MM() { std::cout<<"Destroy # "<<this<<std::endl; }
};
int main()
{
//Fill a vector with some stuff
std::vector<boost::any> v;
v.push_back(0);
v.push_back(0);
v.push_back(0);
v.push_back(0);
//Overwrite one entry with one of our objects.
v[0] = MM();
std::cout<<"Copying the vector"<<std::endl;
std::vector<boost::any> w;
w = v;
std::cout<<"Done"<<std::endl;
}
For which I get the output:
Create # 0xbffff6ae
Copy 0xbffff6ae -> 0x100154
Destroy # 0xbffff6ae
Copying the vector
Copy 0x100154 -> 0x100194
Done
Destroy # 0x100194
Destroy # 0x100154
Which is what I expect to see.
EDIT:
In line with your requirements to be able to treat members as some common base-type you'll need something very similar to boost::any, which thankfully is a relatively simple class.
template<typename BASE>
class any_with_base
{
// ... Members as for boost::any
class placeholder
{
virtual BASE * as_base() = 0;
//Other members as in boost::any::placeholder
};
template<typename ValueType>
class holder : public placeholder
{
virtual BASE * as_base() { return (BASE*)&held; }
//Other members as in boost::any::holder<T>
};
BASE* as_base() { return content?content->as_base():0; }
}
Now you should be able to do this:
vector< any_with_base<Base> > v;
v.push_back( DerivedA() );
v.push_back( DerivedB() );
v[0].as_base()->base_fn();
v[1].as_base()->base_fn();
any_cast<DerivedA>(v[0])->only_in_a();
I actually dislike the syntax of any_cast and would use this opportunity to add an "as" member function.. so that I could write the last line as:
v[0].as<DerivedA>()->only_in_a();
Alright, to follow up my comment, there is a way to do this without using boost::any that should offer superior performance in most cases, but it's admittedly a bit more involved. My solution combines two ideas: the use of a holder class that elides the type of its contents, and lightweight custom RTTI. We give the holder class meaningful copy and assignment semantics and we use containers of holders to manage the collection of objects. We use our lightweight RTTI to discover the true types of the objects when necessary. Here's some code to demonstrate what I'm proposing:
#include <vector>
#include <cassert>
#include <iostream>
#include <boost/cast.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/static_assert.hpp>
/// This template makes it possible to enforce the invariant that every type in a
/// hierarchy defines the id( ) function, which is necessary for our RTTI. Using
/// a static assertion, we can force a compile error if a type doesn't provide id( ).
template< typename T >
struct provides_id {
typedef char one;
typedef long two;
template< typename U, std::string const &(U::*)( ) const = &U::id >
struct id_detector { };
template< typename U > static one test( id_detector< U > * );
template< typename U > static two test( ... );
enum { value = sizeof(test<T>(0)) == sizeof(one) };
};
/// Base class for the holder. It elides the true type of the object that it holds,
/// providing access only through the base class interface. Since there is only one
/// derived type, there is no risk of forgetting to define the clone() function.
template< typename T >
struct holder_impl_base {
virtual ~holder_impl_base( ) { }
virtual T *as_base( ) = 0;
virtual T const *as_base( ) const = 0;
virtual holder_impl_base *clone( ) const = 0;
};
/// The one and only implementation of the holder_impl_base interface. It stores
/// a derived type instance and provides access to it through the base class interface.
/// Note the use of static assert to force the derived type to define the id( )
/// function that we use to recover the instance's true type.
template< typename T, typename U >
struct holder_impl : public holder_impl_base< T > {
BOOST_STATIC_ASSERT(( provides_id< U >::value ));
holder_impl( U const &p_data )
: m_data( p_data )
{ }
virtual holder_impl *clone( ) const {
return new holder_impl( *this );
}
virtual T *as_base( ) {
return &m_data;
}
virtual T const *as_base( ) const {
return &m_data;
}
private:
U m_data;
};
/// The holder that we actually use in our code. It can be constructed from an instance
/// of any type that derives from T and it uses a holder_impl to elide the type of the
/// instance. It provides meaningful copy and assignment semantics that we are looking
/// for.
template< typename T >
struct holder {
template< typename U >
holder( U const &p_data )
: m_impl( new holder_impl< T, U >( p_data ))
{ }
holder( holder const &p_other )
: m_impl( p_other.m_impl -> clone( ))
{ }
template< typename U >
holder &operator = ( U const &p_data ) {
m_impl.reset( new holder_impl< T, U >( p_data ));
return *this;
}
holder &operator = ( holder const &p_other ) {
if( this != &p_other ) {
m_impl.reset( p_other.m_impl -> clone( ));
}
return *this;
}
T *as_base( ) {
return m_impl -> as_base( );
}
T const *as_base( ) const {
return m_impl -> as_base( );
}
/// The next two functions are what we use to cast elements to their "true" types.
/// They use our custom RTTI (which is guaranteed to be defined due to our static
/// assertion) to check if the "true" type of the object in a holder is the same as
/// as the template argument. If so, they return a pointer to the object; otherwise
/// they return NULL.
template< typename U >
U *as( ) {
T *base = as_base( );
if( base -> id( ) == U::static_id( )) {
return boost::polymorphic_downcast< U * >( base );
}
return 0;
}
template< typename U >
U const *as( ) const {
T *base = as_base( );
if( base -> id( ) == U::static_id( )) {
return boost::polymorphic_downcast< U const * >( base );
}
return 0;
}
private:
boost::scoped_ptr< holder_impl_base< T > > m_impl;
};
/// A base type and a couple derived types to demonstrate the technique.
struct base {
virtual ~base( )
{ }
virtual std::string const &id( ) const = 0;
};
struct derived1 : public base {
std::string const &id( ) const {
return c_id;
}
static std::string const &static_id( ) {
return c_id;
}
private:
static std::string const c_id;
};
std::string const derived1::c_id( "derived1" );
struct derived2 : public base {
std::string const &id( ) const {
return c_id;
}
static std::string const &static_id( ) {
return c_id;
}
private:
static std::string const c_id;
};
std::string const derived2::c_id( "derived2" );
/// A program to demonstrate that the technique works as advertised.
int main( ) {
std::vector< holder< base > > vector1;
vector1.push_back( derived1( ));
vector1.push_back( derived2( ));
std::vector< holder< base > > vector2 = vector1;
/// We see that we have true copies!
assert( vector1[0].as_base( ) != vector2[0].as_base( ));
assert( vector1[1].as_base( ) != vector2[0].as_base( ));
/// Easy assignment of container elements to new instances!
vector2[0] = derived2( );
vector2[1] = derived1( );
// Recovery of the "true" types!
std::vector< holder< base > >::iterator l_itr = vector1.begin( );
std::vector< holder< base > >::iterator l_end = vector1.end ( );
for( ; l_itr != l_end; ++l_itr ) {
if( derived1 *ptr = l_itr -> as< derived1 >( )) {
std::cout << ptr -> static_id( ) << std::endl;
}
else if( derived2 *ptr = l_itr -> as< derived2 >( )) {
std::cout << ptr -> static_id( ) << std::endl;
}
}
}
And here's the output:
derived1
derived2
I'm attempting to write a simple ScopeGuard based on Alexandrescu concepts but with c++11 idioms.
namespace RAII
{
template< typename Lambda >
class ScopeGuard
{
mutable bool committed;
Lambda rollbackLambda;
public:
ScopeGuard( const Lambda& _l) : committed(false) , rollbackLambda(_l) {}
template< typename AdquireLambda >
ScopeGuard( const AdquireLambda& _al , const Lambda& _l) : committed(false) , rollbackLambda(_l)
{
_al();
}
~ScopeGuard()
{
if (!committed)
rollbackLambda();
}
inline void commit() const { committed = true; }
};
template< typename aLambda , typename rLambda>
const ScopeGuard< rLambda >& makeScopeGuard( const aLambda& _a , const rLambda& _r)
{
return ScopeGuard< rLambda >( _a , _r );
}
template<typename rLambda>
const ScopeGuard< rLambda >& makeScopeGuard(const rLambda& _r)
{
return ScopeGuard< rLambda >(_r );
}
}
Here is the usage:
void SomeFuncThatShouldBehaveAtomicallyInCaseOfExceptions()
{
std::vector<int> myVec;
std::vector<int> someOtherVec;
myVec.push_back(5);
//first constructor, adquire happens elsewhere
const auto& a = RAII::makeScopeGuard( [&]() { myVec.pop_back(); } );
//sintactically neater, since everything happens in a single line
const auto& b = RAII::makeScopeGuard( [&]() { someOtherVec.push_back(42); }
, [&]() { someOtherVec.pop_back(); } );
b.commit();
a.commit();
}
Since my version is way shorter than most examples out there (like Boost ScopeExit) i'm wondering what specialties i'm leaving out. Hopefully i'm in a 80/20 scenario here (where i got 80 percent of neatness with 20 percent of lines of code), but i couldn't help but wonder if i'm missing something important, or is there some shortcoming worth mentioning of this version of the ScopeGuard idiom
thanks!
Edit I noticed a very important issue with the makeScopeGuard that takes the adquire lambda in the constructor. If the adquire lambda throws, then the release lambda is never called, because the scope guard was never fully constructed. In many cases, this is the desired behavior, but i feel that sometimes a version that will invoke rollback if a throw happens is desired as well:
//WARNING: only safe if adquire lambda does not throw, otherwise release lambda is never invoked, because the scope guard never finished initialistion..
template< typename aLambda , typename rLambda>
ScopeGuard< rLambda > // return by value is the preferred C++11 way.
makeScopeGuardThatDoesNOTRollbackIfAdquireThrows( aLambda&& _a , rLambda&& _r) // again perfect forwarding
{
return ScopeGuard< rLambda >( std::forward<aLambda>(_a) , std::forward<rLambda>(_r )); // *** no longer UB, because we're returning by value
}
template< typename aLambda , typename rLambda>
ScopeGuard< rLambda > // return by value is the preferred C++11 way.
makeScopeGuardThatDoesRollbackIfAdquireThrows( aLambda&& _a , rLambda&& _r) // again perfect forwarding
{
auto scope = ScopeGuard< rLambda >(std::forward<rLambda>(_r )); // *** no longer UB, because we're returning by value
_a();
return scope;
}
so for completeness, i want to put in here the complete code, including tests:
#include <vector>
namespace RAII
{
template< typename Lambda >
class ScopeGuard
{
bool committed;
Lambda rollbackLambda;
public:
ScopeGuard( const Lambda& _l) : committed(false) , rollbackLambda(_l) {}
ScopeGuard( const ScopeGuard& _sc) : committed(false) , rollbackLambda(_sc.rollbackLambda)
{
if (_sc.committed)
committed = true;
else
_sc.commit();
}
ScopeGuard( ScopeGuard&& _sc) : committed(false) , rollbackLambda(_sc.rollbackLambda)
{
if (_sc.committed)
committed = true;
else
_sc.commit();
}
//WARNING: only safe if adquire lambda does not throw, otherwise release lambda is never invoked, because the scope guard never finished initialistion..
template< typename AdquireLambda >
ScopeGuard( const AdquireLambda& _al , const Lambda& _l) : committed(false) , rollbackLambda(_l)
{
std::forward<AdquireLambda>(_al)();
}
//WARNING: only safe if adquire lambda does not throw, otherwise release lambda is never invoked, because the scope guard never finished initialistion..
template< typename AdquireLambda, typename L >
ScopeGuard( AdquireLambda&& _al , L&& _l) : committed(false) , rollbackLambda(std::forward<L>(_l))
{
std::forward<AdquireLambda>(_al)(); // just in case the functor has &&-qualified operator()
}
~ScopeGuard()
{
if (!committed)
rollbackLambda();
}
inline void commit() { committed = true; }
};
//WARNING: only safe if adquire lambda does not throw, otherwise release lambda is never invoked, because the scope guard never finished initialistion..
template< typename aLambda , typename rLambda>
ScopeGuard< rLambda > // return by value is the preferred C++11 way.
makeScopeGuardThatDoesNOTRollbackIfAdquireThrows( aLambda&& _a , rLambda&& _r) // again perfect forwarding
{
return ScopeGuard< rLambda >( std::forward<aLambda>(_a) , std::forward<rLambda>(_r )); // *** no longer UB, because we're returning by value
}
template< typename aLambda , typename rLambda>
ScopeGuard< rLambda > // return by value is the preferred C++11 way.
makeScopeGuardThatDoesRollbackIfAdquireThrows( aLambda&& _a , rLambda&& _r) // again perfect forwarding
{
auto scope = ScopeGuard< rLambda >(std::forward<rLambda>(_r )); // *** no longer UB, because we're returning by value
_a();
return scope;
}
template<typename rLambda>
ScopeGuard< rLambda > makeScopeGuard(rLambda&& _r)
{
return ScopeGuard< rLambda >( std::forward<rLambda>(_r ));
}
namespace basic_usage
{
struct Test
{
std::vector<int> myVec;
std::vector<int> someOtherVec;
bool shouldThrow;
void run()
{
shouldThrow = true;
try
{
SomeFuncThatShouldBehaveAtomicallyInCaseOfExceptionsUsingScopeGuardsThatDoesNOTRollbackIfAdquireThrows();
} catch (...)
{
AssertMsg( myVec.size() == 0 && someOtherVec.size() == 0 , "rollback did not work");
}
shouldThrow = false;
SomeFuncThatShouldBehaveAtomicallyInCaseOfExceptionsUsingScopeGuardsThatDoesNOTRollbackIfAdquireThrows();
AssertMsg( myVec.size() == 1 && someOtherVec.size() == 1 , "unexpected end state");
shouldThrow = true;
myVec.clear(); someOtherVec.clear();
try
{
SomeFuncThatShouldBehaveAtomicallyInCaseOfExceptionsUsingScopeGuardsThatDoesRollbackIfAdquireThrows();
} catch (...)
{
AssertMsg( myVec.size() == 0 && someOtherVec.size() == 0 , "rollback did not work");
}
}
void SomeFuncThatShouldBehaveAtomicallyInCaseOfExceptionsUsingScopeGuardsThatDoesNOTRollbackIfAdquireThrows() //throw()
{
myVec.push_back(42);
auto a = RAII::makeScopeGuard( [&]() { HAssertMsg( myVec.size() > 0 , "attempt to call pop_back() in empty myVec"); myVec.pop_back(); } );
auto b = RAII::makeScopeGuardThatDoesNOTRollbackIfAdquireThrows( [&]() { someOtherVec.push_back(42); }
, [&]() { HAssertMsg( myVec.size() > 0 , "attempt to call pop_back() in empty someOtherVec"); someOtherVec.pop_back(); } );
if (shouldThrow) throw 1;
b.commit();
a.commit();
}
void SomeFuncThatShouldBehaveAtomicallyInCaseOfExceptionsUsingScopeGuardsThatDoesRollbackIfAdquireThrows() //throw()
{
myVec.push_back(42);
auto a = RAII::makeScopeGuard( [&]() { HAssertMsg( myVec.size() > 0 , "attempt to call pop_back() in empty myVec"); myVec.pop_back(); } );
auto b = RAII::makeScopeGuardThatDoesRollbackIfAdquireThrows( [&]() { someOtherVec.push_back(42); if (shouldThrow) throw 1; }
, [&]() { HAssertMsg( myVec.size() > 0 , "attempt to call pop_back() in empty someOtherVec"); someOtherVec.pop_back(); } );
b.commit();
a.commit();
}
};
}
}
Even shorter: I don't know why you guys insist on putting the template on the guard class.
#include <functional>
class scope_guard {
public:
template<class Callable>
scope_guard(Callable && undo_func) try : f(std::forward<Callable>(undo_func)) {
} catch(...) {
undo_func();
throw;
}
scope_guard(scope_guard && other) : f(std::move(other.f)) {
other.f = nullptr;
}
~scope_guard() {
if(f) f(); // must not throw
}
void dismiss() noexcept {
f = nullptr;
}
scope_guard(const scope_guard&) = delete;
void operator = (const scope_guard&) = delete;
private:
std::function<void()> f;
};
Note that it is essential that the cleanup code does not throw, otherwise you get in similar situations as with throwing destructors.
Usage:
// do step 1
step1();
scope_guard guard1 = [&]() {
// revert step 1
revert1();
};
// step 2
step2();
guard1.dismiss();
My inspiration was the same DrDobbs article as for the OP.
Edit 2017/2018: After watching (some of) Andrei's presentation that André linked to (I skipped to the end where it said "Painfully Close to Ideal!") I realized that it's doable. Most of the time you don't want to have extra guards for everything. You just do stuff, and in the end it either succeeds or rollback should happen.
Edit 2018: Added execution policy which removed the necessity of the dismiss call.
#include <functional>
#include <deque>
class scope_guard {
public:
enum execution { always, no_exception, exception };
scope_guard(scope_guard &&) = default;
explicit scope_guard(execution policy = always) : policy(policy) {}
template<class Callable>
scope_guard(Callable && func, execution policy = always) : policy(policy) {
this->operator += <Callable>(std::forward<Callable>(func));
}
template<class Callable>
scope_guard& operator += (Callable && func) try {
handlers.emplace_front(std::forward<Callable>(func));
return *this;
} catch(...) {
if(policy != no_exception) func();
throw;
}
~scope_guard() {
if(policy == always || (std::uncaught_exception() == (policy == exception))) {
for(auto &f : handlers) try {
f(); // must not throw
} catch(...) { /* std::terminate(); ? */ }
}
}
void dismiss() noexcept {
handlers.clear();
}
private:
scope_guard(const scope_guard&) = delete;
void operator = (const scope_guard&) = delete;
std::deque<std::function<void()>> handlers;
execution policy = always;
};
Usage:
scope_guard scope_exit, scope_fail(scope_guard::execution::exception);
action1();
scope_exit += [](){ cleanup1(); };
scope_fail += [](){ rollback1(); };
action2();
scope_exit += [](){ cleanup2(); };
scope_fail += [](){ rollback2(); };
// ...
Boost.ScopeExit is a macro that needs to work with non-C++11 code, i.e. code that has no access to lambdas in the language. It uses some clever template hacks (like abusing the ambiguity that arises from using < for both templates and comparison operators!) and the preprocessor to emulate lambda features. That's why the code is longer.
The code shown is also buggy (which is probably the strongest reason to use an existing solution): it invokes undefined behaviour due to returning references to temporaries.
Since you're trying to use C++11 features, the code could be improved a lot by using move semantics, rvalue references and perfect-forwarding:
template< typename Lambda >
class ScopeGuard
{
bool committed; // not mutable
Lambda rollbackLambda;
public:
// make sure this is not a copy ctor
template <typename L,
DisableIf<std::is_same<RemoveReference<RemoveCv<L>>, ScopeGuard<Lambda>>> =_
>
/* see http://loungecpp.net/w/EnableIf_in_C%2B%2B11
* and http://stackoverflow.com/q/10180552/46642 for info on DisableIf
*/
explicit ScopeGuard(L&& _l)
// explicit, unless you want implicit conversions from *everything*
: committed(false)
, rollbackLambda(std::forward<L>(_l)) // avoid copying unless necessary
{}
template< typename AdquireLambda, typename L >
ScopeGuard( AdquireLambda&& _al , L&& _l) : committed(false) , rollbackLambda(std::forward<L>(_l))
{
std::forward<AdquireLambda>(_al)(); // just in case the functor has &&-qualified operator()
}
// move constructor
ScopeGuard(ScopeGuard&& that)
: committed(that.committed)
, rollbackLambda(std::move(that.rollbackLambda)) {
that.committed = true;
}
~ScopeGuard()
{
if (!committed)
rollbackLambda(); // what if this throws?
}
void commit() { committed = true; } // no need for const
};
template< typename aLambda , typename rLambda>
ScopeGuard< rLambda > // return by value is the preferred C++11 way.
makeScopeGuard( aLambda&& _a , rLambda&& _r) // again perfect forwarding
{
return ScopeGuard< rLambda >( std::forward<aLambda>(_a) , std::forward<rLambda>(_r )); // *** no longer UB, because we're returning by value
}
template<typename rLambda>
ScopeGuard< rLambda > makeScopeGuard(rLambda&& _r)
{
return ScopeGuard< rLambda >( std::forward<rLambda>(_r ));
}
You might be interested in seeing this presentation by Andrei himself on his own taken on how to improve scopedguard with c++11
You can use std::unique_ptr for that purpose which implements the RAII pattern.
For example:
vector<int> v{};
v.push_back(42);
unique_ptr<decltype(v), function<void(decltype(v)*)>>
p{&v, [] (decltype(v)* v) { if (uncaught_exception()) { v->pop_back(); }}};
throw exception(); // rollback
p.release(); // explicit commit
The deleter function from the unique_ptr p rolls the formerly inserted value back, if the scope was left while an exception is active. If you prefer an explicit commit, you can remove the uncaugth_exception() question in the deleter function and add at the end of the block p.release() which releases the pointer. See Demo here.
I use this works like a charm, no extra code.
shared_ptr<int> x(NULL, [&](int *) { CloseResource(); });
There's a chance this approach will be standardized in C++17 or in the Library Fundamentals TS through proposal P0052R0
template <typename EF>
scope_exit<see below> make_scope_exit(EF &&exit_function) noexcept;
template <typename EF>
scope_exit<see below> make_scope_fail(EF && exit_function) noexcept;
template <typename EF>
scope_exit<see below> make_scope_success(EF && exit_function) noexcept;
On first glance this has the same caveat as std::async because you have to store the return value or the destructor will be called immediately and it won't work as expected.
Most of the other solutions involve a move of a lambda, e.g. by using the lambda argument to initialize a std::function or an object of type deduced from the lambda.
Here's one that is quite simple, and allows using a named lambda without moving it (requires C++17):
template<typename F>
struct OnExit
{
F func;
OnExit(F&& f): func(std::forward<F>(f)) {}
~OnExit() { func(); }
};
template<typename F> OnExit(F&& frv) -> OnExit<F>;
int main()
{
auto func = []{ };
OnExit x(func); // No move, F& refers to func
OnExit y([]{}); // Lambda is moved to F.
}
The deduction guide makes F deduce as lvalue reference when the argument is an lvalue.
Without commitment tracking, but extremely neat and fast.
template <typename F>
struct ScopeExit {
ScopeExit(F&& f) : m_f(std::forward<F>(f)) {}
~ScopeExit() { m_f(); }
F m_f;
};
template <typename F>
ScopeExit<F> makeScopeExit(F&& f) {
return ScopeExit<F>(std::forward<F>(f));
};
#define STRING_JOIN(arg1, arg2) STRING_JOIN2(arg1, arg2)
#define STRING_JOIN2(arg1, arg2) arg1 ## arg2
#define ON_SCOPE_EXIT(code) auto STRING_JOIN(scopeExit, __LINE__) = makeScopeExit([&](){code;})
Usage
{
puts("a");
auto _ = makeScopeExit([]() { puts("b"); });
// More readable with a macro
ON_SCOPE_EXIT(puts("c"));
} # prints a, c, b
makeScopeGuard returns a const reference. You can't store this const reference in a const ref at the caller's side in a line like:
const auto& a = RAII::makeScopeGuard( [&]() { myVec.pop_back(); } );
So you are invoking undefined behaviour.
Herb Sutter GOTW 88 gives some background about storing values in const references.
FWIW I think that Andrei Alexandrescu has used a pretty neat syntax in his CppCon 2015's talk about "Declarative Control Flow" (video, slides).
The following code is heavily inspired by it:
Try It Online
GitHub Gist
#include <iostream>
#include <type_traits>
#include <utility>
using std::cout;
using std::endl;
template <typename F>
struct ScopeExitGuard
{
public:
struct Init
{
template <typename G>
ScopeExitGuard<typename std::remove_reference<G>::type>
operator+(G&& onScopeExit_)
{
return {false, std::forward<G>(onScopeExit_)};
}
};
private:
bool m_callOnScopeExit = false;
mutable F m_onScopeExit;
public:
ScopeExitGuard() = delete;
template <typename G> ScopeExitGuard(const ScopeExitGuard<G>&) = delete;
template <typename G> void operator=(const ScopeExitGuard<G>&) = delete;
template <typename G> void operator=(ScopeExitGuard<G>&&) = delete;
ScopeExitGuard(const bool callOnScopeExit_, F&& onScopeExit_)
: m_callOnScopeExit(callOnScopeExit_)
, m_onScopeExit(std::forward<F>(onScopeExit_))
{}
template <typename G>
ScopeExitGuard(ScopeExitGuard<G>&& other)
: m_callOnScopeExit(true)
, m_onScopeExit(std::move(other.m_onScopeExit))
{
other.m_callOnScopeExit = false;
}
~ScopeExitGuard()
{
if (m_callOnScopeExit)
{
m_onScopeExit();
}
}
};
#define ON_SCOPE_EXIT_GUARD_VAR_2(line_num) _scope_exit_guard_ ## line_num ## _
#define ON_SCOPE_EXIT_GUARD_VAR(line_num) ON_SCOPE_EXIT_GUARD_VAR_2(line_num)
// usage
// ON_SCOPE_EXIT <callable>
//
// example
// ON_SCOPE_EXIT [] { cout << "bye" << endl; };
#define ON_SCOPE_EXIT \
const auto ON_SCOPE_EXIT_GUARD_VAR(__LINE__) \
= ScopeExitGuard<void*>::Init{} + /* the trailing '+' is the trick to the call syntax ;) */
int main()
{
ON_SCOPE_EXIT [] {
cout << "on scope exit 1" << endl;
};
ON_SCOPE_EXIT [] {
cout << "on scope exit 2" << endl;
};
cout << "in scope" << endl; // "in scope"
}
// "on scope exit 2"
// "on scope exit 1"
For your usecase, you might also be interested in std::uncaught_exception() and std::uncaught_exceptions() to know whether your exiting the scope "normally" or after an exception has been thrown:
ON_SCOPE_EXIT [] {
if (std::uncaught_exception()) {
cout << "an exception has been thrown" << endl;
}
else {
cout << "we're probably ok" << endl;
}
};
HTH
Here is one I came up with in C++17. It is trivial to port it to C++11 and/or add deactivation option:
template<class F>
struct scope_guard
{
F f_;
~scope_guard() { f_(); }
};
template<class F> scope_guard(F) -> scope_guard<F>;
Usage:
void foo()
{
scope_guard sg1{ []{...} };
auto sg2 = scope_guard{ []{...} };
}
Edit: In same key here is the guard that goes off only "on exception":
#include <exception>
template<class F>
struct xguard
{
F f_;
int count_ = std::uncaught_exceptions();
~xguard() { if (std::uncaught_exceptions() != count_) f_(); }
};
template<class F> xguard(F) -> xguard<F>;
Usage:
void foobar()
{
xguard xg{ []{...} };
...
// no need to deactivate if everything is good
xguard{ []{...} }, // will go off only if foo() or bar() throw
foo(),
bar();
// 2nd guard is no longer alive here
}
Here's another one, now a variation on #kwarnke's:
std::vector< int > v{ };
v.push_back( 42 );
std::shared_ptr< void > guard( nullptr , [ & v ] ( auto )
{
v.pop_back( );
} );
You already chosen an answer, but I'll take the challenge anyway:
#include <iostream>
#include <type_traits>
#include <utility>
template < typename RollbackLambda >
class ScopeGuard;
template < typename RollbackLambda >
auto make_ScopeGuard( RollbackLambda &&r ) -> ScopeGuard<typename
std::decay<RollbackLambda>::type>;
template < typename RollbackLambda >
class ScopeGuard
{
// The input may have any of: cv-qualifiers, l-value reference, or both;
// so I don't do an exact template match. I want the return to be just
// "ScopeGuard," but I can't figure it out right now, so I'll make every
// version a friend.
template < typename AnyRollbackLambda >
friend
auto make_ScopeGuard( AnyRollbackLambda && ) -> ScopeGuard<typename
std::decay<AnyRollbackLambda>::type>;
public:
using lambda_type = RollbackLambda;
private:
// Keep the lambda, of course, and if you really need it at the end
bool committed;
lambda_type rollback;
// Keep the main constructor private so regular creation goes through the
// external function.
explicit ScopeGuard( lambda_type rollback_action )
: committed{ false }, rollback{ std::move(rollback_action) }
{}
public:
// Do allow moves
ScopeGuard( ScopeGuard &&that )
: committed{ that.committed }, rollback{ std::move(that.rollback) }
{ that.committed = true; }
ScopeGuard( ScopeGuard const & ) = delete;
// Cancel the roll-back from being called.
void commit() { committed = true; }
// The magic happens in the destructor.
// (Too bad that there's still no way, AFAIK, to reliably check if you're
// already in exception-caused stack unwinding. For now, we just hope the
// roll-back doesn't throw.)
~ScopeGuard() { if (not committed) rollback(); }
};
template < typename RollbackLambda >
auto make_ScopeGuard( RollbackLambda &&r ) -> ScopeGuard<typename
std::decay<RollbackLambda>::type>
{
using std::forward;
return ScopeGuard<typename std::decay<RollbackLambda>::type>{
forward<RollbackLambda>(r) };
}
template < typename ActionLambda, typename RollbackLambda >
auto make_ScopeGuard( ActionLambda && a, RollbackLambda &&r, bool
roll_back_if_action_throws ) -> ScopeGuard<typename
std::decay<RollbackLambda>::type>
{
using std::forward;
if ( not roll_back_if_action_throws ) forward<ActionLambda>(a)();
auto result = make_ScopeGuard( forward<RollbackLambda>(r) );
if ( roll_back_if_action_throws ) forward<ActionLambda>(a)();
return result;
}
int main()
{
auto aa = make_ScopeGuard( []{std::cout << "Woah" << '\n';} );
int b = 1;
try {
auto bb = make_ScopeGuard( [&]{b *= 2; throw b;}, [&]{b = 0;}, true );
} catch (...) {}
std::cout << b++ << '\n';
try {
auto bb = make_ScopeGuard( [&]{b *= 2; throw b;}, [&]{b = 0;}, false );
} catch (...) {}
std::cout << b++ << '\n';
return 0;
}
// Should write: "0", "2", and "Woah" in that order on separate lines.
Instead of having creation functions and a constructor, you limited to just the creation functions, with the main constructor being private. I couldn't figure out how to limit the friend-ed instantiations to just the ones involving the current template parameter. (Maybe because the parameter is mentioned only in the return type.) Maybe a fix to that can be asked on this site. Since the first action doesn't need to be stored, it's present only in the creation functions. There's a Boolean parameter to flag if throwing from the first action triggers a roll-back or not.
The std::decay part strips both cv-qualifiers and reference markers. But you can't use it for this general purpose if the input type is a built-in array, since it'll apply the array-to-pointer conversion too.
Yet another answer, but I am afraid I find the others all lacking in one way or another. Notably, the accepted answer dates from 2012, but it has an important bug (see this comment). This shows the importance of testing.
Here is an implementation of a >=C++11 scope_guard that is openly available and extensively tested. It is meant to be/have:
modern, elegant, simple (mostly single-function interface and no macros)
general (accepts any callable that respects preconditions)
carefully documented
thin callback wrapping (no added std::function or virtual table penalties)
proper exception specifications
See also the full list of features.
Consider I have the following struct:
struct IDirect3D
{
IDirect3D() : ref_count_(0) {}
unsigned long Release() { return --ref_count_; }
private:
long ref_count_;
~IDirect3D() {}
};
I want to use shared_ptr to it like in the followed code (minimal example):
int main()
{
boost::shared_ptr<IDirect3D> ptr;
IDirect3D* p = 0; // initialized somewhere
ptr.reset( p, boost::mem_fn( &IDirect3D::Release ) );
return 0;
}
This works OK in most cases, but crases if p in equal to 0. I have the following deleter which I want to use:
template<typename T, typename D>
inline void SafeDeleter( T*& p, D d )
{
if ( p != NULL ) {
(p->*d)();
p = NULL;
}
}
But the following code gives a lot of error (looks like it dumps the whole bind.hpp):
ptr.reset( p, boost::bind( SafeDeleter, _1, &IDirect3D::Release ) );
What's wrong with my using of bind?
Release() comes from IUnknown- so why not just use that:
void my_deleter(IUnknown* p) {
// ...
}
ptr.reset(p, &my_deleter);
Note that Boost also has an intrusive_ptr which would seem more natural here:
void intrusive_ptr_add_ref(IUnknown* p) { p->AddRef (); }
void intrusive_ptr_release(IUnknown* p) { p->Release(); }
boost::intrusive_ptr<IDirect3D> d3d(...);
IDirect3D* p = 0;
d3d.reset(p);
Your actual issue is probably that there is a non-template function SafeDeleter - to specifically use the template-function you'd have to use something like:
ptr.reset(p, boost::bind(&SafeDeleter<IDirect3D, ULONG (IDirect3D::*)()>,
_1, &IDirect3D::Release));