Scoped handle (C Plus Plus)

From LiteratePrograms

Jump to: navigation, search

This is a simple template class making it possible to use the RAII technique on variables without a destructor.

Implementation

<<scoped_handle.hpp>>=
#ifndef SCOPED_HANDLE_HPP_INCLUDE_GUARD
#define SCOPED_HANDLE_HPP_INCLUDE_GUARD
namespace lp {
handle_valid
scoped_handle
}
#endif

We use a template with these parameters:

  • T - The data type of the handle
  • CF - The close function (used by the destructor)
  • VF - A function telling if the handle is valid, and optionally invalidating it
<<scoped_handle>>=
template<typename T, int (CF)(T), bool (VF)(T, bool)=handle_valid<T> > class scoped_handle
{
	T handle;
public:
	scoped_handle(T handle_): handle(handle_) {}

This destructor uses VF() to check if the handle is valid, and close it with CF() if it is.

<<scoped_handle>>=
	~scoped_handle() {
		if(VF(handle)) CF(handle);
	}

The handle can be closed manually with this function. We use VF() to invalidate the handle, so that the destructor doesn't try to close it.

<<scoped_handle>>=
	void close() {
		if(VF(handle)) CF(handle);
		VF(handle, true);
	}

We might want to disassociate the handle from the scoped_handle object. release() provides this functionality.

<<scoped_handle>>=
	void release() {
		VF(handle, true);
	}

We provide operator T(), so that the scoped_handle object can be used as if it was an object of type T.

<<scoped_handle>>=
	operator T() {
		return handle;
	}
};

We provide a templated default function for checking/setting validity. This function simply uses 0 as a special value indicating the handle is invalid. This will work for types like FILE * and pointers allocated with malloc(). For other types, like file descriptors/sockets, the user can specialize this template, or specify another function as the third template argument to scoped_handle.

<<handle_valid>>=
template<typename T> inline bool handle_valid(T handle, bool invalidate=false) 
{
	if(invalidate) handle=0;
	return (bool)handle;
}

Test driver

This example program uses scoped_handle for a FILE * variable. When specifying fclose() as the second template argument, we know the file will be closed when leaving the scope.

<<test.cpp>>=
#include"scoped_handle.hpp"
#include<stdio.h>
#include<iostream>
int main()
{
	lp::scoped_handle<FILE*, fclose> file(fopen("test.txt", "w"));
	if(!(FILE*)file) {
		std::cerr<<"Could not open file \"test.txt\" for writing\n";
		return 1;
	}
	fprintf(file, "Hello\n");
	return 0;
}
Download code
Views