JKop said:
The latest (sorry about the non-standard header):
#include <iostream>
#include <windows.h>
template<class T, void (&CleanUp)(T&,bool&)>
^^^^^^^^^^^^^^^^^^^^^^^^^
If you make this a (regular?) parameter (e.g., to the contructor)
rather than a template parameter, you will only instantiate the
template for every T, not for every (T,CleanUp) pair.
class AutoDestructive
{
private:
AutoDestructive(const AutoDestructive&);
AutoDestructive& operator=(const AutoDestructive&);
AutoDestructive* operator&();
const AutoDestructive* operator&() const;
private:
mutable T t;
public:
T& t_ref;
mutable bool to_be_auto_destructed;
AutoDestructive() : t(), t_ref(t), to_be_auto_destructed(false) {}
~AutoDestructive() { ManualCleanUp(); }
T& operator()() { return t_ref; }
const T& operator()() const { return t_ref; }
void ManualCleanUp()
{
CleanUp(t,to_be_auto_destructed);
}
};
IIRC, someone pointed out in an earlier version of this code that
using 'to_be_auto_destucted' is very unnatural, especially since you
require a free function which takes this parameter. The class should
control whether or not the cleanup occurs. Here is an alternative:
template <typename T>
class my_RefProctor {
// This class provides exception safety for an
// object of type T, held by reference.
public:
typedef void (*Callback)(T&); // cleanup callback
private:
T& d_object; // proctored object (held)
Callback d_callback; // user-specified callback
int d_cleanup; // true if cleanup should be done
private:
// not implemented
my_RefProctor(const my_RefProctor&);
my_RefProctor& operator=(const my_RefProctor&);
public:
my_RefProctor(T& object, Callback callback);
// Create a 'my_RefProctor' object to provide exception
// safety for the specified 'object' using the specified
// 'callback' function. The behavior is undefined unless
// 'object' and 'callback' are valid objects.
~my_RefProctor();
// Perform some cleanup for the proctored object by
// calling the stored callback function if 'd_cleanup'
// is 'true'.
void release();
// Release the maintained object from this proctor; no
// cleanup will be done.
};
void CleanUp_HKEY(HKEY& hkey, bool& to_be_closed)
{
if (to_be_closed)
{
RegCloseKey(hkey);
to_be_closed = false;
}
}
typedef AutoDestructive<HKEY,CleanUp_HKEY> AutoDestructive_HKEY;
[snip]
int main()
{
AutoDestructive_HKEY hkey;
LONG error_code = RegOpenKeyEx(HKEY_CLASSES_ROOT,
"*",
0,
KEY_QUERY_VALUE|KEY_SET_VALUE,
&hkey());
if (error_code == ERROR_SUCCESS)
{
hkey.to_be_auto_destructed = true;
}
//Some suff, exception might get thrown here
hkey.ManualCleanUp(); [...]
}
This becomes
int main()
{
HKEY hkey;
LONG rc = RegOpenKeyEx(HKEY_CLASSES_ROOT,
"*", 0, KEY_QUERY_VALUE|KEY_SET_VALUE, hkey);
if (rc != ERROR_SUCCESS) {
// handle error
}
my_RefProctor<HKEY> proctor(hkey, RegCloseKey);
// Some stuff which may throw an exception
proctor.release(); // no exceptions
// further processing
RegCloseKey(hkey);
return 0;
}
This is much more natural as it does no assignments to public members,
does not use or require application-layer wrapper functions, and
conforms to common library usage rather than executing library APIs
through some indirect method.
HTH, /david