12.4.2的C ++标准指出
[...]不得采用析构函数的地址。 [...]
然而,编译器可以毫无怨言地采用类析构函数周围的包装器的地址,如下所示:
struct Test {
~Test(){};
void destructor(){
this->~Test();
}
};
void (Test::*d)() = &Test::destructor;
那么禁止直接获取析构函数地址的理由是什么?
答案 0 :(得分:17)
构造函数和析构函数有点特殊。编译器经常 在调用它们时使用不同的约定(例如,传递额外的隐藏 参数)。如果你拿走了地址并将其保存在某个地方,那么 编译器会丢失该函数是构造函数的信息 或析构函数,并且不知道使用特殊约定。
答案 1 :(得分:0)
关于调用约定的其他答案可能有所不同,这是一个原因。
但是我也想:尚不清楚有用对析构函数的地址到底有多大作用!你会用它做什么?调用它可能非常不安全-您是否会将它用于相等性比较?要确定对象的确切类型,也许?还有其他语言工具。
最终,如果析构函数作为函数发出,它确实具有一个地址-但是该语言会考虑将该地址用于任何内容,即使相等比较也是如此,因此非常无用,只是在语言级别被禁止
从技术上讲,编译器可以允许您执行此操作-可能将其强制为void *指针或其他内容-但随后必须指定确切的地址。编译器甚至不会将琐碎类的析构函数作为函数发出析构函数,也并非总是如此-因此,获取地址将要求它这样做。
这可能仅对平等比较有用,并且-定义平等保证的内容可能不值得,因为其他语言工具也可能实现相同的目的。
Tl; Dr:只是被认为是不安全的而且没有用,所以该语言禁止使用它。
答案 2 :(得分:0)
显然不能保证析构函数存在。如果您尝试以下操作并检查反汇编,您会注意到没有调用析构函数,也没有可引用的析构函数。
https://godbolt.org/z/6nYWf48Gz
struct Foo {
Foo() {}
int a = 3;
};
void fizz() {
Foo foo;
}
int main() {
Foo foo;
foo.~Foo(); // call destructor if exists, otherwise noop
fizz();
return 0;
}