【问题标题】:C++: casting to void* and backC++:强制转换为 void* 并返回
【发布时间】:2011-01-07 09:56:00
【问题描述】:

* --- 编辑 - 现在是整个源代码*

最后调试时,“get”和“value”的值不同!可能,我转换为 void* 并以错误的方式返回给用户?

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

解决方案

创建一种“序列化器”,它将所有 POD 转换为 void*,然后将这些部分联合起来

PS 或者我将 User 重写为 POD 类型,我希望一切都会好起来的。

添加

这很奇怪,但是...我将一个明确的非 pod 对象转换为 void* 并返回(它内部有 std::string)并且没关系(没有将其发送到数据库并返回)。怎么会这样?在我投递并发送“槽”db 后,我明确地发送了 pod 对象(没有额外的方法,所有成员都是 pod,这是一个简单的 struct {int a; int b; ...})我得到了一个肮脏的东西。我的方法有什么问题?

在第一次“添加”后大约一周添加

该死的...我已经编译了它,只是为了看看它返回什么样的污垢,哦!没关系!...我不能! ... 啊!.. 上帝... 一个合理的问题(在 99.999% 的情况下,正确答案是“我的”,但是...这里...) - 这是谁的错?我的还是 VS?

【问题讨论】:

  • 我知道,我知道这个问题被问了很多次……但我没有找到任何合理的答案……
  • M... 它应该是 &get 所在的 get.get_data() - 但它什么也没做。
  • 我没有重复 - 这个问题是关于 ->associate 和这个在同一个项目上但有另一个问题。
  • 我注意到 get 和 put 发生在同一个数据库事务中。事务中的操作顺序是否为您保证?

标签: c++ berkeley-db void-pointers


【解决方案1】:

除非UserPOD,否则这在 C++ 中是未定义的。

编辑:

看看db_cxx.h,你不应该调用get_doff()get_dlen()get_data()Dbt 上的其他东西,而不是仅仅将其转换(并分配)给用户类型吗?

【讨论】:

  • 我不像我看起来的那么傻。 :) 只是,我写过:“Db 和 Env 以及类似的一切都已经存在” - 一切都可以编译!但是启动后,最终“……”get“和”value“的值不同……”
  • @Mlnner:仅仅因为它编译并不意味着行为被定义。
  • 正确...如果 User 是一个包含方法、构造函数等的类,您不能将其作为普通数据转储到数据库中,您需要编写逻辑来处理“序列化”并“反序列化”它。
  • @Nikolai N Fetissov:对……对不起……@davr:那我该怎么做呢?
  • 它被称为“未定义行为”,即它可以做任何事情 - 擦除你的硬盘,打电话给 FBI,吃掉你的孩子,或者像你描述的那样行事 :)
【解决方案2】:

由于没有检查 put() 的返回值,因此很可能存在阻止更新的错误。 The documentation 表示不少错误条件:

【讨论】:

  • 它返回零,所以没关系,不是吗?
  • 如果返回零,则认为一切正常。
【解决方案3】:

您几乎绝对不应该将“get”直接投射给用户。相反,提取您存储的数据,然后进行转换。除非您与我们分享 Dbt 的定义,否则我们无法确定。根据我们可以看到的内容进行猜测:

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

告诉我们更多关于 Dbt 的信息,我们或许可以为您提供更多帮助。

【讨论】:

    【解决方案4】:

    我会这样做:

    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
    

    然后提取它看起来像这样:

    //// Get from DB
    
    std::string        dbStore(get.get_data(),get.get_date() + get.get_size());
    std::stringstream  dbStoreStream(dbStore);
    User              outUser;
    
     dbStoreStream >> outUSer;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-21
      • 1970-01-01
      • 2011-10-25
      • 1970-01-01
      • 2011-04-03
      相关资源
      最近更新 更多