We have seen that a simple fine-grained swizzling mechanism is not as desirable because of its unusual interactions with the operating system and the virtual memory system. However, we can slightly modify the basic technique and overcome most of the disadvantages without losing any of the benefits.
The solution is to implement smart pointers that are translated on every use and avoid any caching of the translated value. In other words, these smart pointers hold only the persistent addresses, and must be translated every time they are dereferenced because the virtual addresses are not cached. Equality checks do not incur any overhead because the pointer fields are always in the same representation and can be compared directly.
Pointer dereferences also do not incur any additional checking overhead. The cost of translating at each use does not add much overhead to the overall cost, and is usually amortized over other ``work'' done by the application; that is, the application may dereference a smart pointer and then do some computation with the resulting target object before dereferencing another smart pointer.
The advantage of this approach is that the pointer fields do not need to be modified because the translated address values are never cached, and all unwanted interactions with checkpointing and the virtual memory system are avoided. Of course, this approach is still unsuitable as a general swizzling mechanism compared to the pointer swizzling at page fault time for reasons described in Section 4.