第5.16章: 指针最佳实践
概述
在学习了指针如何工作以及需要避免的许多陷阱之后,本章 总结在现代 C++ 中安全、清晰地使用指针的最佳实践。
你将学到:
- 如何正确地初始化指针
- 如何使用 const 正确性
- 如何安全地获取地址
- 如何从迭代器中取出原始指针
- 如何安全地做类型双关
- 如何正确地使用内存函数
- 如何安全地清除机密数据
- 如何写出清晰、可维护的指针代码
1. 始终初始化指针
指针应始终初始化为有效对象,或者初始化为
nullptr。
int x{42};
int *p = ::std::addressof(x); // ✔ good
int *q{}; // ✔ initialized to nullptr
2. 只读数据使用 T const*
这遵循第2.8章的规则:const 作用于左边。
就这样。
char const *s = "Hello"; // ✔ correct for C-style strings
const 正确性可防止意外修改。
3. 使用 ::std::addressof 而不是 &
& 可以被重载。::std::addressof 总是返回
对象的真实地址。
4. 对迭代器使用 ::std::to_address
::std::to_address 从任何行为类似指针的迭代器中
取出原始指针。
auto it = v.begin();
int *p = ::std::to_address(it); // ✔ universal pointer extraction
5. 类型双关使用 memcpy 或 ::std::bit_cast
永远不要用 reinterpret_cast 做类型双关。它会违反严格
别名规则(第5.13章)。
float f{1.0f};
std::uint32_t u = ::std::bit_cast<std::uint32_t>(f); // ✔ safe
6. 不确定是否重叠时使用 memmove
对重叠内存使用 memcpy 是未定义行为。
memmove 始终安全。
7. 调用内存函数之前始终检查 size != 0
用 nullptr 配非零大小调用 memcpy、memmove、
memcmp 或 memchr 是未定义
行为。
if (n != 0) {
::std::memcpy(dst, src, n);
}
8. 机密数据使用 ::fast_io::secure_clear
memset 可能被优化掉。
::fast_io::secure_clear 保证内存确实被擦除。
char secret[32]{};
::fast_io::secure_clear(secret, sizeof(secret)); // ✔ secure
9. 保持指针算术简单
尽可能优先使用索引。避免花哨的指针技巧。
10. 尊重对象的生命周期
指针不会延长它所指向对象的生命周期。
11. 避免 reinterpret_cast
它几乎总是错的。
请改用 memcpy 或 ::std::bit_cast。
12. 尽可能优先使用更高层的抽象
指针很强大但也很危险。请有意识地使用它们,而不是随手使用。
要点
- 把指针初始化为有效对象或
nullptr。 - 只读数据使用
T const*。 - 使用
::std::addressof与::std::to_address。 - 类型双关使用
memcpy或::std::bit_cast。 - 不确定是否重叠时使用
memmove。 - 调用内存函数之前始终检查
size != 0。 - 擦除机密数据使用
::fast_io::secure_clear。 - 保持指针算术简单,并尊重生命周期。
- 避免
reinterpret_cast。