🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
## addressof ### 头文件: `"boost/utility.hpp"` 要取得一个变量的地址,我们要依赖于返回的值是否真的是这个变量的地址。但是,技术上重载`operator&`是有可能的,这意味着存有恶意的人可以破坏你的地址相关的代码。`boost::addressof` 被用于获得变量的地址,不管取址操作符是否被误用。通过使用一些灵巧的内部机制,模板函数 `addressof` 确保可以获得真实的对象及其地址。 ### 用法 为确保获得一个对象的真实地址,你要使用 `boost::addressof`. 它定义在 `"boost/utility.hpp"`. 它常用于原本要使用 `operator&` 的地方,它接受一个参数,该参数为要获得地址的那个对象的引用。 ``` #include "boost/utility.hpp" class some_class {}; int main() { some_class s; some_class* p=boost::addressof(s); } ``` 在进一步学习如何使用 `addressof`的细节前,了解一下`operator&`为何以及如何不一定会返回对象的地址是非常有用的。 ### 快速了解一下存有恶意的人 如果你真的,真的,真的需要重载 `operator&`, 或者只是想试验一下操作符重载可能的用法,这的确很容易。当你重载 `operator&`时,它的语义肯定会与多数用户(以及函数!)所期望的不同,所以千万不要为了好玩而做这件事;除非有非常好的理由,否则不要去做它。以下有一段code-breaker代码: ``` class codebreaker { public: int operator&() const { return 13; } }; ``` 对于这个类,任何人想获取一个`codebreaker`实例的地址都会得到一个不可思议的数字13. ``` template <typename T> void print_address(const T& t) { std::cout << "Address: " << (&t) << '\n'; } int main() { codebreaker c; print_address(c); } ``` 这不难做到,但是在实际的代码中这样做有没有好的理由?也许没有,因为除非是用在局部的类上,否则它是不安全的。原因是,虽然获取一个不完整类型的地址是合法的,但如果是要获取一个带有用户自定义`operator&`的不完整类型的地址则是未定义的行为。因为我们不能保证这不会发生,所以我们最好不要重载 `operator&`. ### 迅速的解决方法 即使一个类的 `operator&` 被重载了,也还是有办法获得这个类的实例的真实地址。`addressof` 使用了一些幕后的巧妙方法\[6\]来获得真实的地址,而不会受任何 `operator&` 的欺骗。如果你把函数(`print_address`)改为使用 `addressof`, 你就可以得到以下代码: > \[6\] 非常出名的一种ingenious hack. ``` template <typename T> void print_address(const T& t) { std::cout << "&t: " << (&t) << '\n'; std::cout << "addressof(t): " << boost::addressof(t) << '\n'; } ``` 执行时,该函数将给出如下输出(或类似于以下的输出,因为准确的地址值取决于你的系统). ``` &t: 13 addressof(t): 0012FECB13 ``` 差不多就是这样了!如果有什么情况让你知道或怀疑一个类的`operator&`被重载了,而你又需要确保得到真实的地址(由于 `operator&` 被重载而变得不可信了), 你就应该使用 `addressof`. ### 总结 没有多少有力的论点支持重载 `operator&`,\[7\] 但由于这是可能的,总有些人会这样做。当你编写一些需要依赖于获得对象真实地址的代码时,`addressof` 可以帮助你确保得到真实的地址。在编写泛型代码时,没有办法知道将会操作什么类型,因此如果需要获取参数化类型的地址的话,就使用 `addressof`. > \[7\] 即使是定制的硬件设备驱动程序 当你需要获得一个对象的真实地址时,使用 `addressof` ,不必管 `operator&` 的语义。