Ch5.16: Pointer Best Practices
Overview
After learning how pointers work and the many pitfalls to avoid, this chapter summarizes the best practices for using pointers safely and clearly in modern C++.
You will learn:
- how to initialize pointers correctly
- how to use const-correctness
- how to obtain addresses safely
- how to extract raw pointers from iterators
- how to type-pun safely
- how to use memfunctions correctly
- how to clear secrets securely
- how to write clear, maintainable pointer code
1. Always initialize pointers
A pointer should always be initialized to a valid object or to
nullptr.
int x{42};
int *p = ::std::addressof(x); // ✔ good
int *q{}; // ✔ initialized to nullptr
2. Use T const* for read-only data
This follows the rule from Ch2.8: const applies to the
left. Full stop.
char const *s = "Hello"; // ✔ correct for C-style strings
Const-correctness prevents accidental modification.
3. Use ::std::addressof instead of &
& can be overloaded. ::std::addressof always returns
the true address of an object.
4. Use ::std::to_address for iterators
::std::to_address extracts a raw pointer from any iterator that
behaves like a pointer.
auto it = v.begin();
int *p = ::std::to_address(it); // ✔ universal pointer extraction
5. Use memcpy or ::std::bit_cast for type punning
Never use reinterpret_cast for type punning. It violates strict
aliasing (Ch5.13).
float f{1.0f};
std::uint32_t u = ::std::bit_cast<std::uint32_t>(f); // ✔ safe
6. Use memmove when unsure about overlap
memcpy is undefined behavior for overlapping memory.
memmove is always safe.
7. Always check size != 0 before memfunctions
Calling memcpy, memmove, memcmp, or
memchr with nullptr and non-zero size is undefined
behavior.
if (n != 0) {
::std::memcpy(dst, src, n);
}
8. Use ::fast_io::secure_clear for secrets
memset may be optimized away.
::fast_io::secure_clear guarantees that memory is actually erased.
char secret[32]{};
::fast_io::secure_clear(secret, sizeof(secret)); // ✔ secure
9. Keep pointer arithmetic simple
Prefer indexing when possible. Avoid clever pointer tricks.
10. Respect object lifetimes
A pointer does not extend the lifetime of the object it points to.
11. Avoid reinterpret_cast
It is almost always wrong.
Use memcpy or ::std::bit_cast instead.
12. Prefer higher-level abstractions when possible
Pointers are powerful but dangerous. Use them deliberately, not casually.
Key takeaways
- Initialize pointers to valid objects or
nullptr. - Use
T const*for read-only data. - Use
::std::addressofand::std::to_address. - Use
memcpyor::std::bit_castfor type punning. - Use
memmovewhen unsure about overlap. - Always check
size != 0before memfunctions. - Use
::fast_io::secure_clearto erase secrets. - Keep pointer arithmetic simple and respect lifetimes.
- Avoid
reinterpret_cast.