views:

439

answers:

4

* ---Edit - now the whole sourse*

When I debug it on the end, "get" and "value" have different values! Probably, I convert to void* and back to User the wrong way?

#include <db_cxx.h>
#include <stdio.h>

struct User{
User(){}
int name;
int town;
User(int a){};
inline int get_index(int a){
    return town;
} //for another stuff
};
int main(){ 
try {
DbEnv* env = new DbEnv(NULL);
env->open("./", 
    DB_CREATE | DB_INIT_MPOOL | DB_THREAD | 
DB_INIT_LOCK | DB_INIT_TXN | DB_RECOVER | DB_INIT_LOG, 0);
Db* datab = new Db(env, 0);
datab->open(NULL, "db.dbf", NULL, DB_BTREE, DB_CREATE | DB_AUTO_COMMIT, 0);

Dbt key, value, get;
char a[10] = "bbaaccd";
User u;
u.name = 1;
u.town = 34;
key.set_data(a);
key.set_size(strlen(a) + 1 );
value.set_data((void*)&u);
value.set_size(sizeof(u));
get.set_flags(DB_DBT_MALLOC);

DbTxn* txn;
env->txn_begin(NULL, &txn, 0);
datab->put(txn, &key, &value, 0);
datab->get(txn, &key, &get, 0);
txn->commit(0);
User g;
g = *((User*)&get);
printf("%d", g.town);
getchar();
return 0;
}catch (DbException &e){
    printf("%s", e.what());
    getchar();
}

solution

create a kind of "serializator" what would convert all POD's into void* and then will unite these pieces

PS Or I'd rewrite User into POD type and everything will be all right, I hope.

Add

It's strange, but... I cast a defenetly non-pod object to void* and back (it has std::string inside) and it's all right (without sending it to the db and back). How could it be? And after I cast and send 'trough' db defenetly pod object (no extra methods, all members are pod, it's a simple struct {int a; int b; ...}) I get back dirted one. What's wrong with my approach?

Add about week after first 'add'

Damn... I've compiled it ones, just for have a look at which kind of dirt it returnes, and oh! it's okay!... I can't ! ... AAh!.. Lord... A reasonable question (in 99.999 percent of situations right answer is 'my', but... here...) - whos is this fault? My or VSs?

+7  A: 

Unless User is a POD this is undefined in C++.

Edit:

Looking at db_cxx.h, aren't you supposed to do call get_doff(), get_dlen(), and get_data() or something on Dbt instead of just casting (and assigning) it to the user type?

Nikolai N Fetissov
I'm not as fool as I could look like. :) Just, I've wrote: "Db and Env and everything like this already exists" - everything compiles all right! But after startup, in the end "... "get" and "value" have different values..."
MInner
@Mlnner: Just because it compiles doesn't mean the behavior is defined.
John Dibling
Correct...if User is a class containing methods, constructors, etc, you can't just dump it to database as a plain piece of data, you need to write logic to handle "serializing" and "unserializing" it.
davr
@Nikolai N Fetissov: right... sorry...@davr: Then, how should I do that?
MInner
Yeah... I'd need to write a "serializing" method... Okay... (I havn't cought it in BDB Guide, somehow...)
MInner
It's strange, but when I picked a std::string into class and it was all right after casting it to void* and back - it means I've understood something wrong... I can simply cast any of POD-like types, because it's clear where any element (field) of information should be. But when we use classes, returning different sizeof()'s - it means that it's not clear where any field is in mem. So, how I casted std::string consisting class to void* and back? And what's wrong it listing upthere? (If it casts to void* and back without BD all right, and wrong way with DB)?May be there is a kind of specia way?
MInner
It's called 'undefined behavior', i.e. it can do anything - erase you hard drive, call FBI, eat your kids, or behave as you described :)
Nikolai N Fetissov
Well, is there any ideas of how should code with defined behavior look like? :) (if it already casts defenetly pod-like structures, and after picking them into db and back they become dirtied...)
MInner
In my second comment on question I've told about that. It should be get.get_data() here. Now it works (see my last 'add').
MInner
+1  A: 

Since there is no check of the return value of put(), it could well be there is an error which prevented updating. The documentation indicates quite a few error condtions:

wallyk
It returns zero, so it's okay, isn't it?
MInner
If it returns zero, it thinks all is well.
wallyk
+1  A: 

You are almost definitely NOT supposed to cast 'get' directly to a User. Instead, extract the data you stored and then cast that. We can't know for sure unless you share with us the definition of Dbt. Making a guess, based on what we can see:

datab->get(txn, &key, &get, 0);
void* data = get.get_data();
User g = *((User*)data);

Tell us more about Dbt and we can probably help you out more.

Darryl
Dbt is a part of BDB :)
MInner
A: 

I would do something like this:

User               user;
std::stringstream  dbStotrStream;

dbStoreStream << user;  // Serialize user
std::string        dbStore(bdStoreStream.str());
value.set_data(dbStore.c_str());  
value.set_size(dbStore.lenght());

////  Put in DB

Then extracting it would look like this:

//// Get from DB

std::string        dbStore(get.get_data(),get.get_date() + get.get_size());
std::stringstream  dbStoreStream(dbStore);
User              outUser;

 dbStoreStream >> outUSer;
Martin York