Using templates can remove the need to manually define the delete function. It can also be used to further extend into a custom wrapper to deal with the other parts you mentioned as well such as:
PHP Code:
template<typename T>
struct auto_cleanup_impl;
template<>
struct auto_cleanup_impl<HANDLE>
{
static void cleanup(HANDLE value)
{
if (value != INVALID_HANDLE_VALUE) ::CloseHandle(value);
}
};
template<typename T>
class auto_cleanup
{
std::shared_ptr<void> value_;
public:
auto_cleanup(T value)
: value_{ value, auto_cleanup_impl<T>::cleanup }
{}
~auto_cleanup(void)
{}
T get(void) const
{
return this->value_.get();
}
};
Then in the same manner can be used as:
PHP Code:
auto_cleanup val(::OpenProcess(PROCESS_VM_OPERATION, FALSE, 1));
To allow for direct value usage of the underlying shared pointer, one can add the overloads needed:
PHP Code:
operator T() const { return value_.get(); }
auto_cleanup<T>& operator=(T const& val)
{
this->value_.reset(val, auto_cleanup_impl<T>::cleanup);
return *this;
}
Then additional constructors can be added if you need default value handling or other kinds of initialization.
PHP Code:
// Implementations will depend on the supported types etc.
auto_cleanup()
: value_{ nullptr, auto_cleanup_impl<T>::cleanup }
{}
To extend the types supported, you only need to add an auto_cleanup_impl entry for the given type. For example, to add support for a FILE pointer, it can be added via:
PHP Code:
template<>
struct auto_cleanup_impl<FILE*>
{
static void cleanup(FILE* value)
{
if (value) ::fclose(value);
}
};
Some examples of using this with a HANDLE type would be:
PHP Code:
// Wrapped initialization; type determined by the return of the called function..
auto_cleanup val1(::OpenProcess(PROCESS_VM_OPERATION, FALSE, 1));
// Default initialization; type determined by the value type..
auto_cleanup val2{ INVALID_HANDLE_VALUE };
// Default initialization; type determined by explicit template usage..
auto_cleanup<HANDLE> val3{};
// Value usage after creation..
uint8_t buffer[1024]{};
auto_cleanup val4{ INVALID_HANDLE_VALUE };
val4 = ::OpenProcess(PROCESS_VM_OPERATION, FALSE, 1);
::ReadProcessMemory(val4, reinterpret_cast<LPCVOID>(0x1234ABCD), &buffer, 1024, nullptr);