通过绑定到已删除的派生对象的基类指针调用虚方法有什么效果
以下问题是:
- b 被销毁后,p->test() 不应该起作用。但是,代码运行没有任何问题,动态绑定仍然有效;
- 当定义 A 的析构函数时,动态绑定不再起作用。其背后的逻辑是什么?
#include <iostream>
using namespace std;
struct A {
//~A() {}
virtual void test() { cout << 0 << endl; }
};
class B :public A {
void test() { cout << 1 << endl; }
};
int main() {
A* p;
{
B b;
p = &b;
}
p->test(); // the method called will be different if the destructor of A is removed
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
它不“工作”。
p->test()
调用未定义的行为。除了您正在使用的编译器的实现细节之外,它背后没有任何逻辑,因为 C++ 标准没有强制编译器应该如何处理具有未定义行为的代码。
有关未定义行为的更多详细信息,我建议您访问 https://en.cppreference.com/ w/cpp/language/ub
编译器无法检测到所有未定义的行为,但只能检测到其中的一些行为。使用 gcc,您可以尝试
-fsanitize=address
更清楚地查看问题:https:// /godbolt.org/z/qxTs4sxcW。It does not "work".
p->test()
invokes undefined behavior.There is no logic behind it, other than implementation details of the compiler you are using, because the C++ standard does not mandate what a compiler should do with code that has undefined behavior.
For more details on undefined behavior I refer you to https://en.cppreference.com/w/cpp/language/ub
Compilers cannot detect all undefined behavior, but some of it. With gcc you can try
-fsanitize=address
to see the issue more clearly: https://godbolt.org/z/qxTs4sxcW.欢迎来到未定义行为的世界!对已删除对象的任何访问(包括调用其方法)都会调用未定义的行为。
这意味着这些语言不需要特定的行为,并且取决于编译器的内部结构以及可能取决于计算机上任何明显不相关的事物,从预期行为(您经历过的行为)到立即发生的任何事情都可能发生立即或稍后发生崩溃或意外结果。
切勿尝试测试 UB 操作的结果:即使配置相同,它也可能从一个编译更改为新的编译,如果依赖于未初始化的内存,甚至可以从一次运行更改为另一次运行。
更糟糕的是:如果编译器可以在代码的一部分中检测到 UB,它就可以优化该部分,因为该语言允许它假设程序永远不应该调用 UB。
TL/DR:您在这里调用 UB。不。只是不要。
Welcome to the world of Undefined Behaviour! Any access to a deleted object, including calling a method on it invokes undefined behaviour.
That means that the languages requires no specific behaviour, and depending on the internals of the compiler and possibly on any apparently unrelated thing on the computer anything can happen from the expected behaviour (you experienced it) to an immediate crash or unexpected results occuring immediately or later.
Never try to test the result of an UB operation: it can change from one compilation to a new one even with the same configuration or even from one run to the other if it depends on uninitialized memory.
Worse: if the compiler can detect UB in a portion of code, it can optimize out that portion because the language allows it to assume that a program should never invoke UB.
TL/DR: you are invoking UB here. Don't. Just don't.