メモリ管理を楽にする
極薄wrapper版、datumの扱いはハダカのままなのでdptrをfree()するのが面倒だし、忘れやしないかとヒヤヒヤですね。使い終わったら勝手にfreeされるよう仕向けましょう。datumから導出し、デストラクタでfree()するauto_datumを用意します。auto_ptr/unique_ptrと同様のカラクリです。
// gdbm_db.h(部分) namespace gdbm { ... struct auto_datum : datum { auto_datum(); auto_datum(datum& d); auto_datum(auto_datum& d); ~auto_datum(); auto_datum& operator=(datum& d); auto_datum& operator=(auto_datum& d); private: void free(); }; bool empty(const datum& d); }
// gdbm_db.cpp(部分) ... namespace gdbm { auto_datum::auto_datum() { dptr = 0; dsize = 0; } auto_datum::auto_datum(datum& d) { dptr = d.dptr; dsize = d.dsize; } auto_datum::auto_datum(auto_datum& d) { dptr = d.dptr; d.dptr = nullptr; dsize = d.dsize; d.dsize = 0; } auto_datum::~auto_datum() { free(); } auto_datum& auto_datum::operator=(datum& d) { if ( this != &d ) { free(); dptr = d.dptr; dsize = d.dsize; } return *this; } auto_datum& auto_datum::operator=(auto_datum& d) { if ( this != &d ) { free(); dptr = d.dptr; d.dptr = nullptr; dsize = d.dsize; d.dsize = 0; } return *this; } void auto_datum::free() { ::free(dptr); dptr = nullptr; } bool empty(const datum& d) { return d.dptr == nullptr; } }
コピー・コンストラクタやコピー・オペレータの扱いが少々ややこしくなっています。fetch/firstkey/secondkey()の戻り値であるdatumをauto_datumで引き取れば、メモリの解放はauto_datum(のデストラクタ)におまかせです。
void store() { gdbm::db dbx("trial.db", 512, GDBM_NEWDB); assert( dbx.is_open() ); array<const char*,4> keys = { "apple", "orange", "grape", "apple" }; array<const char*,4> contents = { "まっく", "みかん", "ぶどう", "りんご" }; datum key; datum content; for ( size_t i = 0; i < keys.size(); ++i ) { key.dptr = const_cast<char*>(keys[i]); key.dsize = strlen(keys[i]) + 1; content.dptr = const_cast<char*>(contents[i]); content.dsize = strlen(contents[i]) + 1; int result = dbx.store(key, content); assert( result == 0 ); } cout << "3 entries stored." << endl; } void fetch() { gdbm::db dbx("trial.db", 512, GDBM_WRCREAT); assert( dbx.is_open() ); array<const char*,4> keys = { "apple", "orange", "grape", "peach" }; for ( const char* target : keys ) { datum key; key.dptr = const_cast<char*>(target); key.dsize = strlen(target) + 1; gdbm::auto_datum content =dbx.fetch(key); if ( empty(content) ) { cout << target << " not found..." << endl; } else { cout << target << " = " << content.dptr << endl; } } cout << "--- list all entries ---" << endl; gdbm::auto_datum key = dbx.firstkey(); while ( !empty(key) ) { gdbm::auto_datum content = dbx.fetch(key); cout << key.dptr << " = " << content.dptr << endl; key = dbx.nextkey(key); } }