【问题标题】:g_hash_table_insert seems to be overriding previously inserted valuesg_hash_table_insert 似乎覆盖了以前插入的值
【发布时间】:2018-08-23 13:24:14
【问题描述】:

我是 GLIB 库的新手。 g_hash_table_insert() 似乎覆盖了以前插入的值。当我打印出保存数据的键和值时,键仍然是唯一的且未更改,但值 ALL 相同。我将struct 类型存储到GHashtable 中,这是它的结构:

struct _DsectionEntity {
  ...
  int entity_type;
  int sequence_number;
  ...
};

typedef struct _DsectionEntity DsectionEntity;

我逐行解析一个IGES模型文件,解析IGES文件D部分的2行后创建DsectionEntity对象。我使用对象的序列号作为键,使用整个对象作为值。创建哈希表和插入值的代码如下:

void
get_dsection(IgesFile *fp, DsectionEntity *ds)
{
  char *line1 = malloc(91);
  char *line2 = malloc(91);

  /* dsection_ht GHashtable declared as a global var and initialized to NULL */
  dsection_ht = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free);

  line1 = get_line(fp, line1);
  while (line1) {
    if (line1[72] == 'D') {
      line2 = get_line(fp, line2);

      /* create Object */
      parser_dsection_new(ds, line1, line2);

      /* insert Object into the hashtable */
      parser_add_ds_object(dsection_ht, ds);
      line1 = get_line(fp, line1);
    } else {
      line1 = get_line(fp, line1);
    }
  }
}

插入代码:

void
parser_add_ds_object(GHashTable * ht, DsectionEntity *dsec_entity)
{
  // printf("KEY : %d\n", GPOINTER_TO_INT(GINT_TO_POINTER(dsec_entity->sequence_number)));
  // printf("SQ : %d\n", dsec_entity->sequence_number);
  // printf("Entity : %d\n", dsec_entity->entity_type);
  // printf("\n");
  g_hash_table_insert(ht, GINT_TO_POINTER(dsec_entity->sequence_number), (gpointer)dsec_entity);
}

如果在 printf 上删除 cmets,则输出(正确)为:

void
print_values(gpointer key, gpointer value, gpointer userdata)
{
  int realkey = GPOINTER_TO_INT(key);
  DsectionEntity *realvalue = (DsectionEntity *)value;

  printf("KEY : %d\n", realkey);
  printf("SQ : %d\n", realvalue->sequence_number);
  printf("Entity : %d\n", realvalue->entity_type);
  printf("====================================\n");
}

如果我使用上面显示的g_hash_table_foreach(dsection_ht, print_values, NULL)print_values() 显示。我得到:

具有重复sequence_numberentity_type 的对象是最后一个添加到GHashtable 中的对象(如图1 所示)。 Valgrind 没有显示错误,那么可能是什么问题?

文件格式为 IGES(初始图形交换规范)。 parser_dsection_new() 的代码:

void
parser_dsection_new(DsectionEntity *dsec_entity, char *line1, char *line2)
{
  char substr[10];

  get_field(line1, substr, 1, 8);
  dsec_entity->entity_type = utils_to_int(substr);

  // ...

  get_field(line1, substr, 74, 8);
  dsec_entity->sequence_number = utils_to_int(substr);

  get_field(line1, substr, 9, 8);
  dsec_entity->line_weight = utils_to_int(substr);

  get_field(line1, substr, 17, 8);
  dsec_entity->color = utils_to_int(substr);

  get_field(line1, substr, 57, 8);
  dsec_entity->entity_label = substr;
  // ...
}

【问题讨论】:

  • @AnttiHaapala 我不明白你所说的 2 个对象是什么意思。
  • @Minathe:请更新您的文件格式以及parser_dsection_new函数的定义。
  • @Minathe:你能检查一下g_hash_table_insert的返回值是TRUE还是FALSE?您可能需要在 if 中移动这些打印以检查例如if ( g_hash_table_insert(...) == TRUE ) { /* print values */ }.
  • @Azeem OUTPUT is LIKE IMAGE 1 i.stack.imgur.com/dmPB4.png 所有值都打印正确。
  • 已解决!!!在parser_add_ds_object(dsection_ht, ds);之后添加ds = (DsectionEntity *) malloc(sizeof(DsectionEntity));

标签: c hashtable glib


【解决方案1】:

根据g_hash_table_insert()的参考:

将新的键和值插入 GHashTable。

如果键已存在于 GHashTable 中,则其当前值将替换为新值。如果您在创建 GHashTable 时提供了 value_destroy_func,则使用该函数释放旧值。如果您在创建 GHashTable 时提供了 key_destroy_func,则使用该函数释放传递的密钥。

因此,g_hash_table_insert() API 应该用新值替换现有值。


但是,您的问题是您只使用 DsectionEntity 的一个实例进行所有操作,即解析、插入等,而每次您想要在哈希。在您的代码中,相同的实例被覆盖,这就是您只看到最新值的原因。使用唯一的实例,它会起作用。

您可以像这样使用g_hash_table_new_full()g_hash_table_remove_all() 中的默认删除功能:

// Create hash table with default delete callbacks
ht = g_hash_table_new_full(g_direct_hash, g_direct_equal, g_free, g_free);
//                                                        ~~~~~~  ~~~~~~

// Allocate new entry
ds = (DsectionEntity*) malloc( sizeof(DsectionEntity) );

// Populate entry
// ...

// Insert entry in hash table
g_hash_table_insert( ht, 
                     GINT_TO_POINTER( ds->sequence_number ), 
                     (gpointer) ds);

// ^^^ Do check the return value of g_hash_table_insert

// Remove hash table at the end
g_hash_table_remove_all( ht );

查看此example 以获得指导。


替代方案:

您可能想探索 UT Hash 作为替代哈希表解决方案。

【讨论】:

    猜你喜欢
    • 2020-06-23
    • 2016-04-11
    • 1970-01-01
    • 1970-01-01
    • 2014-01-12
    • 1970-01-01
    • 2010-11-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多