I have been trying to come up with a way to get around some of the shortcomings of the HDF5 C++ bindings. Currently, my code is littered with try/catch blocks similar to the following:
H5::Exception::dontPrint();
H5::H5File *file = NULL;
try {
file = new H5::H5File(fname.c_str(), H5F_ACC_RDWR);
} catch(H5::FileIException &file_exists_err) {
file = new H5::H5File(fname.c_str(), H5F_ACC_TRUNC);
}
This shouldn't be necessary - all I want to do is to open a file for read/write access, and if it doesn't exist, to create it. Another, trickier problem is to create a nested group (e.g. "/parent/group"), where the parent group does not necessarily exist. In Unix/Linux, the equivalent would be
mkdir -p parent/group
However, in the HDF5 C++ bindings, creating a group whose parent group does not exist raises an exception.
For these reasons, I have been motivated to create a header file which deals with some of these common problems. My first thought was to simply create a set of functions that would, for example, take a filename and access mode and return an H5::H5File object, or take a group name and return a group object. I think this is less than ideal, however, as it leaves the programmer who uses this header file to call "delete" on the returned objects, even though the programmer never explicitly calls "new" in their own code. This seems to be asking for memory leaks.
My second thought, therefore, was to create a set of derived classes from H5::H5File and H5::H5Group, with constructors that do not throw exceptions when the file does not yet exist, or when the group's parent group does not yet exist. My attempt for the derived file class was as follows:
namespace H5Utils {
class H5File : public H5::H5File {
public:
H5File(std::string fname);
~H5File();
};
}
H5Utils::H5File::H5File(std::string fname)
try : H5::H5File(fname.c_str(), H5F_ACC_RDWR)
{
std::cerr << "Opened existing file." << std::endl;
} catch(H5::FileIException &file_exists_err) {
std::cerr << "File does not exist. Creating new file." << std::endl;
H5::H5File(fname.c_str(), H5F_ACC_TRUNC);
}
H5Utils::H5File::~H5File() { }
The problem that I am running into is twofold. First, the try/catch block in the constructor re-throws the exception created by
H5::H5File(fname.c_str(), H5F_ACC_RDWR)
when the file does not exist, so program still terminates. The second problem is that I am not sure that the second constructor,
H5::H5File(fname.c_str(), H5F_ACC_TRUNC);
is correct (i.e. does it construct the parent class?) Is there a way to have the derived class catch exceptions in the base class' constructor, and then call a different constructor for the base class?
More generally, can anyone think of a better/more elegant way of dealing with these shortcomings of the HDF5 C++ bindings?
I prefer your initial idea of create some simple helper functions - it will be simpler and minimise the amount of code you'll have to write and document. Additionally, to ensure proper memory management, you can use shared_ptr
.
Here's a simple wrapper function equivalent to your initial example:
// a typedef for our managed H5File pointer
typedef std::shared_ptr<H5::H5File> H5FilePtr;
// create or open a file
H5FilePtr create_or_open(const std::string& fname)
{
H5::Exception::dontPrint();
H5::H5File* file = 0;
try {
file = new H5::H5File(fname.c_str(), H5F_ACC_RDWR);
} catch(const H5::FileIException&) {
file = new H5::H5File(fname.c_str(), H5F_ACC_TRUNC);
}
return H5FilePtr(file);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With