I'm not saying never do that (ok, maybe I am...) But definitely think long and hard about how long your code will be around before you do it.
That's why you hide the trick behind a zero-cost abstraction which checks at compile-time if the platform supports this
† Offer only valid in the contiguous United States. Offer cannot be used in combination with any other offers. See stores for details.
‡ When not in use, return Happy Fun Ball™ to its protective lead case.
And if you're willing to check your optimizations by reading disassembly, tricks like stuffing tag bits into the bottom of aligned pointer values is pretty routine.
Cache thrashing is a thing. And perf analysis tools have bookkeeping errors.
What problems did lower bit use cause? You always had to mask it away even on the old boxes, no?
As for struct members, the alignment is (of course) "implementation defined", which is the fancy way of throwing up your hands and saying "whatever". (Since C++11 we actually have alignas(), which at least gives manual control)
For instance, jemalloc(3) on amd64 platforms will give back 16-byte aligned pointers:
[...] The allocated space is suitably aligned
(after possible pointer coercion) for storage of any type of object.But that sort of trick is only worth it if you are writing a compiler and its runtime, an interpreter, a memory allocator (in particular GCs) or at the very last some sort of high performance library (you would return your "featured pointer" as an opaque type to the user).