C++什么时候销毁 vtable?
When is a vtable destroy in C++?
在基类的析构函数中调用虚函数是一种很好的做法吗?">vtable在毁灭时间中存在吗?是否建议在析构函数中调用虚函数?
我可以在基类的析构函数中调用虚函数吗?
从析构函数或构造函数调用虚函数是一种不好的做法。请参阅标准(强调我的):
12.7 建造和破坏
成员函数,包括虚函数 (10.3),可以在构造或销毁 (12.6.2) 期间调用。 当从构造函数或析构函数直接或间接调用虚函数时,包括 在构造或销毁类的非静态数据成员期间,以及 调用应用是正在构建或销毁的对象(调用它x
),调用的函数是最终覆盖器 在构造函数或析构函数的类中,而不是在派生更多的类中重写它。如果虚拟 函数调用使用显式类成员访问 (5.2.5),对象表达式引用完整的x
的对象或该对象的基类子对象之一,但不是x
或其基类子对象之一, 行为未定义。
您可以在许多来源中找到此建议,包括斯科特·迈耶斯(Scott Meyers)的
《有效C++:改进程序和设计的55种特定方法》(第9项:在构建或破坏期间切勿调用虚函数。
或赫伯·萨特的
C++编码标准:101 条规则、指南和最佳实践(49.避免在构造函数和析构函数中调用虚函数)。
是的,当您调用析构函数时,对象将有一个指向其 vtable 的指针。
该标准明确表示可以在析构函数中调用虚函数,并说明了会发生什么。 人们一致认为,即使允许这样做,也是一种不好的做法,因为它本质上是脆弱的代码,会导致看似无辜的更改令人惊讶。
如果你有从Der
继承DerDer
,它继承自Base
,它们都覆盖成员函数void member()
,并且你在Der
的析构函数中,并调用member()
,你正在调用Der::member()
,而不是DerDer::member()
,因为你对象的DerDer
部分已经消失了,已经被销毁了。 基类可能会无意中引用派生类中的数据,例如:
struct Base {
int *ip;
Base(int *ip): ip(ip) {}
virtual void useInt() { std::cout << *ip << std::endl; }
~Base() { useInt(); }
};
struct Der: Base {
int theInt;
Der(): Base(&theInt) {}
void useIntPointer() override { std::cout << theInt << std::endl; }
};
当类型为Der
的对象被删除时,存在"未定义的行为":首先调用Der
的隐式析构函数,然后调用Base
的显式析构函数,Base::~Base
。 在这一点上,Base::ip
指的是已经被摧毁的Der
成员。
- 什么时候调用组成单元对象的析构函数
- 什么时候在C++中返回常量引用是个好主意
- 什么时候调用析构函数
- boost odeint什么时候真正调用观测者
- 编译器对数组声明大小的计算。什么时候发生?
- 什么时候最好在子进程中使用 CPU 或 I/O 密集型代码 [ C++ ]
- 您应该在什么时候创建自己的异常类型
- 我什么时候会默认(而不是删除)基类中的复制和移动操作
- 什么时候可以使用常量装饰调用我的重载函数?
- unordered_map什么时候返回 -1?
- QCoreApplication什么时候有效?
- sizeof(size_t) 和 sizeof(ptrdiff_t) 什么时候会有所不同?
- 什么时候用指针调用C++类构造函数
- 我不明白在这个例子中什么时候调用构造函数
- 如果真的需要std::move,我们应该什么时候声明右值refs
- P1008("prohibit aggregates with user-declared constructors")在实践中什么时候有用?
- 程序什么时候会创建多个堆
- 调用boost.asio的异步函数时,线程是什么时候创建的
- Swig/python : 什么时候需要 SWIG_init() ?
- C++什么时候销毁 vtable?