2012-12-12 21 views
8

Ho cercato di trovare un modo per aggirare alcuni dei limiti delle associazioni C++ HDF5. Attualmente, il mio codice è disseminato di blocchi try/catch simili a quanto segue:Un modo migliore per aprire i file HDF5 in C++

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); 
} 

Questo non dovrebbe essere necessario - tutto quello che voglio fare è quello di aprire un file per l'accesso in lettura/scrittura, e se doesn esiste, per crearlo. Un altro problema più complesso consiste nel creare un gruppo nidificato (ad esempio "/ parent/gruppo"), in cui il gruppo principale non esiste necessariamente. In Unix/Linux, l'equivalente sarebbe

mkdir -p parent/group 

Tuttavia, nel HDF5 C++ attacchi, la creazione di un gruppo il cui gruppo principale non esiste solleva un'eccezione.

Per questi motivi, sono stato motivato a creare un file di intestazione che tratta alcuni di questi problemi comuni. Il mio primo pensiero è stato semplicemente creare un insieme di funzioni che, ad esempio, prendessero un nome di file e una modalità di accesso e restituissero un oggetto H5 :: H5File, o prendessero un nome di gruppo e restituissero un oggetto di gruppo. Penso che questo sia tutt'altro che ideale, tuttavia, poiché lascia il programmatore che usa questo file di intestazione per chiamare "delete" sugli oggetti restituiti, anche se il programmatore non chiama esplicitamente "nuovo" nel proprio codice. Questo sembra chiedere perdite di memoria.

Il mio secondo pensiero, quindi, era di creare un set di classi derivate da H5 :: H5File e H5 :: H5Group, con costruttori che non generano eccezioni quando il file non esiste ancora o quando il gruppo principale del gruppo non esiste ancora. Il mio tentativo per la classe di file derivato è stato il seguente:

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() { } 

Il problema che sto funzionando in è duplice. In primo luogo, il blocco try/catch nel costruttore ri-genera l'eccezione creato da

H5::H5File(fname.c_str(), H5F_ACC_RDWR) 

quando il file non esiste, in modo da programma termina ancora. Il secondo problema è che io non sono sicuro che il secondo costruttore,

H5::H5File(fname.c_str(), H5F_ACC_TRUNC); 

è corretto (cioè vuol costruire la classe genitore?) C'è un modo per avere i derivati ​​eccezioni classe di cattura nel costruttore della classe base e quindi chiamare un costruttore diverso per la classe base?

Più in generale, qualcuno può pensare a un modo migliore/più elegante di gestire questi limiti delle associazioni HDF5 C++?

+0

"Un altro, problema più complicato è quello di creare un gruppo nidificato (ad esempio '/ genitore/gruppo'), dove il gruppo padre non necessariamente esiste In Unix/Linux, l'equivalente sarebbe ... . "- Hai mai trovato un bel modo per farlo? –

+2

Se viene assegnato un nome di gruppo nidificato, ad esempio "/ parent/group/subgroup", dividerlo in "/ parent", "/ parent/group" e "/ parent/group/subgroup", quindi prova ad aprire ognuno in ordine. Se un determinato gruppo non esiste (nell'API C++, otterresti un 'H5 :: FileIException'), crealo. Ho scritto [alcune funzioni di supporto che trattano questo problema] (https://github.com/gregreen/h5utils/blob/master/src/h5utils.cpp#L92). – Thucydides411

+0

Aveva lo stesso problema recentemente http://stackoverflow.com/questions/35668056/test-group-existence-in-hdf5-c. Nessuna soluzione. In cima a ciò, ho appena notato che H5 :: Exception non deriva da std :: exception ...? – eudoxos

risposta

8

Preferisco l'idea iniziale di creare alcune semplici funzioni di supporto: sarà più semplice e ridurrà al minimo la quantità di codice che dovrete scrivere e documentare. Inoltre, per garantire una corretta gestione della memoria, è possibile utilizzare shared_ptr.

Ecco una semplice funzione wrapper equivalente al tuo esempio iniziale:

// 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); 
} 
3

Tuttavia, negli attacchi HDF5 C++, la creazione di un gruppo il cui gruppo principale non esiste solleva un'eccezione.

È possibile impostare l'elenco delle proprietà di creazione collegamento su create missing intermediate groups ed evitare questa eccezione.Per esempio:

#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; 
} 
+0

Questo è un altro argomento per l'utilizzo dell'API C, anche quando si scrive in C++. Molte funzionalità mancano nell'API C++ orientata agli oggetti, e alcune scelte progettuali, come lanciare eccezioni invece di impostare i flag, sono piuttosto fastidiose. – Thucydides411

Problemi correlati