Я пытался найти способ обойти некоторые недостатки привязки HDF5 C ++. В настоящее время мой код заполнен блоками try / catch, подобными следующим:
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);
}
В этом не должно быть необходимости — все, что я хочу сделать, — это открыть файл для доступа на чтение / запись, и, если он не существует, создать его. Другая, более сложная проблема заключается в создании вложенной группы (например, «/ parent / group»), в которой родительская группа не обязательно существует. В Unix / Linux эквивалент будет
mkdir -p parent/group
Однако в привязках HDF5 C ++ создание группы, родительская группа которой не существует, вызывает исключение.
По этим причинам я был мотивирован для создания файла заголовка, который решает некоторые из этих распространенных проблем. Моей первой мыслью было просто создать набор функций, которые, например, будут принимать имя файла и режим доступа и возвращать объект H5 :: H5File, или принимать имя группы и возвращать объект группы. Однако я думаю, что это не совсем идеально, поскольку у программиста, который использует этот заголовочный файл, остается вызов «удалить» для возвращаемых объектов, хотя программист никогда не вызывает явно «новый» в своем собственном коде. Кажется, это требует утечек памяти.
Поэтому моей второй мыслью было создание набора производных классов из H5 :: H5File и H5 :: H5Group, с конструкторами, которые не выдают исключений, когда файл еще не существует или когда родительская группа группы еще не существует , Моя попытка получить производный класс файлов была следующей:
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() { }
Проблема, с которой я сталкиваюсь, двояка. Во-первых, блок try / catch в конструкторе повторно генерирует исключение, созданное
H5::H5File(fname.c_str(), H5F_ACC_RDWR)
когда файл не существует, программа все равно завершает работу. Вторая проблема заключается в том, что я не уверен, что второй конструктор,
H5::H5File(fname.c_str(), H5F_ACC_TRUNC);
является правильным (то есть конструирует ли он родительский класс?) Есть ли способ, чтобы производный класс ловил исключения в конструкторе базового класса, а затем вызывал другой конструктор для базового класса?
В более общем плане, может ли кто-нибудь придумать лучший / более элегантный способ устранения этих недостатков привязок HDF5 C ++?
Я предпочитаю вашу первоначальную идею создать несколько простых вспомогательных функций — это будет проще и минимизирует объем кода, который вам придется писать и документировать. Кроме того, чтобы обеспечить правильное управление памятью, вы можете использовать shared_ptr
,
Вот простая функция-оболочка, эквивалентная вашему первоначальному примеру:
// 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);
}
Однако в привязках HDF5 C ++ создание группы, родительская группа которой не существует, вызывает исключение.
Вы можете установить список свойств создания ссылки на создать недостающие промежуточные группы, и избежать этого исключения. Например:
#include "hdf5.h"
int main (void){
hid_t lcpl, file_id, group_id;
herr_t status;
unsigned flag=1;
lcpl = H5Pcreate(H5P_LINK_CREATE);
status = H5Pset_create_intermediate_group(lcpl, flag);
file_id = H5Fcreate("nested_groups.h5", H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
group_id = H5Gcreate( file_id, "/foo/bar/bop", lcpl, H5P_DEFAULT, H5P_DEFAULT );
H5Pclose(lcpl);
H5Gclose(group_id);
H5Fclose(file_id);
return status;
}