Hashing of pointer values
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Hashing a pointer means turning a memory address into a hash code that can be used in structures such as hash tables. That sounds simple, but the important question is what you are trying to identify: the object by its address, or the value stored inside the object.
Pointer Identity and Object Value Are Different
If you hash a pointer directly, you are hashing identity. Two pointers hash the same when they refer to the same address. That is useful for caches, node registries, and graph algorithms where object identity matters.
If you want two separate objects with equal contents to behave as equal keys, then hashing the pointer value is the wrong strategy. In that case, you should hash the pointed-to data instead.
The distinction shows up immediately in C++:
The objects contain the same value, but they have different addresses. A pointer hash would treat them as different keys.
Using Standard Library Pointer Hashing
In modern C++, std::hash<T*> already exists. For many cases, that is enough.
This works because the hash is based on the address, and equality is also based on the address. For identity-based containers, the standard behavior is usually correct and clear.
Why Custom Mixing Can Still Matter
Raw addresses often have predictable low bits because of alignment. If objects are aligned to 8 or 16 bytes, those low bits are frequently zero, and a naive hash can distribute poorly if the hash table implementation does not compensate well.
When you need a custom pointer hasher, convert the pointer to std::uintptr_t and mix the bits before returning a std::size_t.
The exact mixing function is less important than the principle: do not assume raw addresses are already well distributed.
Lifetime and Portability Concerns
Pointer hashes are only meaningful while the pointed-to objects remain alive. Once an object is destroyed, the address may later be reused, and a stale hashed pointer becomes dangerous.
There are a few practical implications:
- never persist pointer hashes to disk as stable identifiers
- never compare pointer hashes across processes
- do not assume the same address will exist after restart
- remember that address space layout randomization changes addresses between runs
If you need a stable key, generate one explicitly, such as a numeric ID or UUID.
Common Pitfalls
- Hashing the pointer when you meant to hash the data behind it. That creates identity semantics instead of value semantics.
- Storing pointers to objects whose lifetime is not guaranteed. A container full of dangling pointers is a correctness bug, not a hashing problem.
- Assuming raw addresses are uniformly distributed. Alignment can reduce entropy in predictable bit positions.
- Treating pointer hashes as portable or persistent. They are process-local implementation details.
Summary
- Hashing a pointer usually means hashing object identity, not object contents.
- '
std::hash<T*>is often enough for identity-based hash tables in C++.' - Custom hashers should mix pointer bits instead of relying on raw addresses directly.
- Pointer hashes are valid only while the objects are alive in the current process.
- Use explicit stable IDs when you need persistence or cross-process comparison.

