Thanks in advance for your votes!
Cheers,
July 2015 Developer's Poll
Re: July 2015 Developer's Poll
I use RAII any time it is even remotely possible. If I don't have a ready-made RAII mechanism for something, I will often write one. Over the years, I have built a pretty decent library of predicates for use with boost::shared_ptr<>, and I make extensive use of a modified version of Andrei Alexandrescu's ScopeGuard template classes.
Here's an example of how I use predicates with boost::shared_ptr<>:
class FindCloser
{
public:
void operator()(HANDLE *handle) const
{ if ( *handle != NULL ) { FindClose( *handle ); *handle = NULL; } }
};
// provide exception safety for the Find resource without resorting to try...finally
boost::shared_ptr<HANDLE> shared_find( &hFindFile, FindCloser() );
Here's a ScopeGuard example:
// make sure pSubcategory is deleted at the end of scope, if guard is not dismissed
ScopeGuard guard = MakeGuard( DeleteSubcategoryPtr, pSubcategory );
And while I do most of my work in C# these days, I find ScopeGuard extremely useful in C# too, not so much for memory resources (thanks to garbage collection), but definitely for certain kinds of resources and especially for reciprocal operations. I ported the ScopeGuard class to C# and use it all the time, like this:
using (var transactionGuard = ScopeGuardFactory.MakeGuard(targetDbSqlTransaction.Rollback))
{
// do some work on the DB that might throw an exception
// commit DB changes
targetDbSqlTransaction.Commit();
// dismiss the transaction guard (prevents unintended Rollback)
transactionGuard.Dismiss();
}
Some of my colleagues have noticed my use of ScopeGuard in C# and have asked about it because they have never seen anything like it before, and when I explain it to them, they like it a lot.
Dennis
Here's an example of how I use predicates with boost::shared_ptr<>:
class FindCloser
{
public:
void operator()(HANDLE *handle) const
{ if ( *handle != NULL ) { FindClose( *handle ); *handle = NULL; } }
};
// provide exception safety for the Find resource without resorting to try...finally
boost::shared_ptr<HANDLE> shared_find( &hFindFile, FindCloser() );
Here's a ScopeGuard example:
// make sure pSubcategory is deleted at the end of scope, if guard is not dismissed
ScopeGuard guard = MakeGuard( DeleteSubcategoryPtr, pSubcategory );
And while I do most of my work in C# these days, I find ScopeGuard extremely useful in C# too, not so much for memory resources (thanks to garbage collection), but definitely for certain kinds of resources and especially for reciprocal operations. I ported the ScopeGuard class to C# and use it all the time, like this:
using (var transactionGuard = ScopeGuardFactory.MakeGuard(targetDbSqlTransaction.Rollback))
{
// do some work on the DB that might throw an exception
// commit DB changes
targetDbSqlTransaction.Commit();
// dismiss the transaction guard (prevents unintended Rollback)
transactionGuard.Dismiss();
}
Some of my colleagues have noticed my use of ScopeGuard in C# and have asked about it because they have never seen anything like it before, and when I explain it to them, they like it a lot.
Dennis
- Damon
- BCBJ Editor and Admin
- Posts: 285
- Joined: Wed May 26, 2004 11:25 pm
- Location: Stillwater, OK, USA
- Contact:
Re: July 2015 Developer's Poll
Great techniques Dennis! Hope you were able to convince some colleagues to adopt the technique or more RAII in general.
Cheers,
Cheers,
Re: July 2015 Developer's Poll
You don't really need a separate FindCloser class with shared_ptr, you can use FindClose() directly as the deleter. And the only thing that the FindCloser class is offering to shared_ptr is automatic assignment of the source variable to NULL. Which, honestly, I wouldn't really bother with in this situation:djones wrote: Here's an example of how I use predicates with boost::shared_ptr<>
Code: Select all
HANDLE hFindFile = FindFirstFile(...);
boost::shared_ptr<void> shared_find( hFindFile, &::FindClose ); // <-- not &hFindFile
Code: Select all
boost::shared_ptr<void> hFindFile( FindFirstFile(...), &::FindClose );
If you intend to use the HANDLE locally and not pass it around, you should actually be using unique_ptr instead:
Code: Select all
class FindCloser
{
public:
typedef HANDLE pointer; // <-- add this
void operator()(HANDLE handle) const // <-- not HANDLE*
{ if ( handle != INVALID_HANDLE_VALUE ) { FindClose( handle ); } }
};
Code: Select all
HANDLE hFindFile = FindFirstFile(...);
boost::unique_ptr<HANDLE, FindCloser> shared_find( hFindFile ); // <-- not &hFindFile
Code: Select all
boost::unique_ptr<HANDLE, FindCloser> hFindFile( FindFirstFile(...) );
Remy Lebeau (TeamB)
Lebeau Software
Lebeau Software