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&
的语义。