メモリ管理を楽にする
極薄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);
}
}
