为什么禁止获取析构函数的地址?

发布于 2024-12-11 22:19:37 字数 358 浏览 0 评论 0原文

C++ 标准 12.4.2 指出

[...] 不应获取析构函数的地址。 [...]

但是,编译器可以毫无怨言地获取类析构函数周围的包装器的地址,如下所示:

struct Test {
    ~Test(){};

    void destructor(){
        this->~Test();
    }
};

void (Test::*d)() = &Test::destructor;

那么禁止直接获取析构函数的地址背后的理由是什么?

C++ standard at 12.4.2 states that

[...] The address of a destructor shall not be taken. [...]

However, one can without any complaints by the compiler take the address of a wrapper around a class destructor, like this:

struct Test {
    ~Test(){};

    void destructor(){
        this->~Test();
    }
};

void (Test::*d)() = &Test::destructor;

So what's the rationale behind forbidding to take the address of a destructor directly?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

拧巴小姐 2024-12-18 22:19:38

显然,析构函数不能保证存在。如果您尝试以下操作并检查反汇编,您会发现没有调用析构函数,也没有可供引用的析构函数。

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;
}

Apparently the destructor is not guaranteed to exist. If you try the following, and check the disassembly, you'll notice there's no call to a destructor nor is there a destructor function to reference.

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;
}
梦中楼上月下 2024-12-18 22:19:37

构造函数和析构函数有些特殊。编译器经常
调用它们时使用不同的约定(例如传递额外的隐藏
论据)。如果您获取了该地址并将其保存在某处,
编译器会丢失该函数是构造函数的信息
或析构函数,并且不知道使用特殊约定。

Constructors and destructors are somewhat special. The compiler often
uses different conventions when calling them (e.g. to pass extra hidden
arguments). If you took the address and saved it somewhere, the
compiler would lose the information that the function is a constructor
or destructor, and would not know to use the special conventions.

若相惜即相离 2024-12-18 22:19:37

其他答案谈到了调用约定可能不同,这是原因之一。

但我也认为:目前尚不清楚获取析构函数的地址到底有多大用处!你会用它做什么?调用它可能非常不安全——你会用它来进行相等比较吗?也许是为了确定对象的确切类型?还有其他语言设施可以实现这一点。

最终,如果析构函数作为函数发出,它确实有一个地址 - 但该语言考虑将该地址用于任何,甚至相等比较也非常没有用,因此在语言级别被禁止。

从技术上讲,编译器可以允许你这样做——也许强制它到一个 void * 指针或其他东西——但随后必须指定你将得到的确切地址。编译器甚至并不总是将普通类的析构函数作为函数发出——因此获取地址需要它这样做。

它可能只对相等比较有用,并且定义相等保证可能不值得,因为其他语言工具也可能实现相同的目标。

Tl;Dr:它只是被认为不安全且无用,因此语言禁止它。

The other answers talked about the calling convention potentially differing, and this is one reason.

But I think also: It's not clear how useful taking the address of a destructor really would be! What would you use it for? Calling it is potentially very unsafe -- would you use it for equality comparisons? To determine the exact type of an object, perhaps? There are other language facilities for that.

Ultimately if the destructor is emitted as a function it does have an address -- but the language considers using that address for anything, even equality comparisons so terribly not useful it's just forbidden at the language level.

Technically the compiler could have allowed you to do it -- perhaps forcing it to a void * pointer or something -- but then it would have to be specified which address exactly you would be given. It's also not always the case that the compiler even emits a destructor for trivial classes as a function -- so taking the address would require it to do so.

It would only be useful for equality comparisons, potentially -- and defining what the equality guarantees are is probably not worth it since other language facilities can potentially achieve the same thing.

Tl;Dr: It's just considered unsafe and not useful, so the language forbids it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文