使用g_hash_table_new_full存储post结构体时出现信息丢失问题求助
Let’s break down why your post data might be disappearing when using GHashTable with g_hash_table_new_full, and walk through actionable fixes for each scenario.
1. Mismatched Hash/Equal Functions for 64-bit IDs
Your hash table uses g_int_hash and g_int_equal—these are built for 32-bit integer keys. But your post struct uses long id, which is 64 bits on most modern systems. This mismatch causes two critical issues:
- Hash collisions: 64-bit IDs get truncated to 32 bits during hashing, so different IDs might map to the same bucket.
- Failed lookups:
g_int_equalonly compares 32 bits of the ID, so valid lookups can returnNULLeven when the entry exists.
Fix:
Swap to 64-bit compatible hash and equality functions:
GHashTable* g_hash_table_posts = g_hash_table_new_full( g_int64_hash, // Properly hashes 64-bit long values g_int64_equal, // Completes full 64-bit comparisons NULL, &free_post );
Ensure all insert/lookup operations use pointers to long (not int) values to match.
2. Invalid Memory Handling for Post Structs
Data loss often stems from bad memory management practices with your post structs:
- Stack-allocated posts: If you insert a post that lives on the stack (not the heap), the memory gets overwritten once the stack frame exits. The hash table will hold a dangling pointer, leading to garbage data or "missing" entries.
- Incomplete cleanup in
free_post: If your cleanup function doesn’t free heap-allocated members liketitleandtags, you’ll get memory leaks—and if it frees the struct before its members, you’ll trigger undefined behavior that can corrupt the hash table.
Fixes:
- Always allocate posts on the heap with
g_mallocormalloc:struct post* new_post = g_malloc(sizeof(struct post)); new_post->title = g_strdup("My First Post"); new_post->tags = g_strdup("c,glib"); // Initialize other fields (id, score, etc.) g_hash_table_insert(g_hash_table_posts, &new_post->id, new_post); - Update
free_postto fully clean up all members:void free_post(gpointer data) { struct post* p = (struct post*)data; g_free(p->title); // Free the heap-allocated title string g_free(p->tags); // Free the tags string g_free(p); // Free the post struct itself }
3. Duplicate ID Overwrites
GHashTable enforces unique keys. If you insert two posts with the same id, the second entry will overwrite the first—making it look like the original post vanished.
Fix:
Add a check before inserting to avoid overwrites:
if (!g_hash_table_contains(g_hash_table_posts, &new_post->id)) { g_hash_table_insert(g_hash_table_posts, &new_post->id, new_post); } else { g_warning("Post with ID %ld already exists", new_post->id); free_post(new_post); // Prevent memory leaks from duplicate posts }
If you need to store multiple posts per ID, adjust the hash table to map keys to GList instances (each list holds all posts for that ID):
GHashTable* g_hash_table_posts = g_hash_table_new_full( g_int64_hash, g_int64_equal, NULL, (GDestroyNotify)g_list_free_full // Frees the list and all posts in it ); // Insert logic for multiple posts per ID GList* post_list = g_hash_table_lookup(g_hash_table_posts, &new_post->id); post_list = g_list_prepend(post_list, new_post); g_hash_table_insert(g_hash_table_posts, &new_post->id, post_list);
4. Incorrect Lookup Logic
Sometimes data isn’t lost—it’s just not being found. Common lookup mistakes include:
- Using an
intpointer instead of alongpointer for the lookup key (mismatching the type expected byg_int64_equal). - Accidentally using
parent_idor another field instead ofidas the lookup key.
Fix:
Double-check your lookup code to ensure you’re passing the correct key type and value:
long target_id = 12345; struct post* found_post = g_hash_table_lookup(g_hash_table_posts, &target_id); if (found_post == NULL) { g_debug("Post with ID %ld could not be found", target_id); }
5. Thread Safety Violations
If you’re accessing the hash table from multiple threads without synchronization, race conditions can corrupt the table’s internal structure—leading to missing entries, crashes, or garbage data. GHashTable is not thread-safe by default.
Fix:
Wrap all hash table operations (insert, lookup, delete) with a GMutex:
GMutex post_table_mutex; // Initialize the mutex once at startup g_mutex_init(&post_table_mutex); // Example lookup with mutex protection g_mutex_lock(&post_table_mutex); struct post* found = g_hash_table_lookup(g_hash_table_posts, &target_id); // Perform operations on the found post... g_mutex_unlock(&post_table_mutex);
内容的提问来源于stack exchange,提问作者Pedro Lima

