调用 ~Derived() 和 ~Base() 之间的对象状态
The state of an object between a call to ~Derived() and ~Base()
问题
C++标准对物体在时间中的状态有什么保证在派生类的析构函数执行之后,但在基类的析构函数执行之前?(这是调用派生类的子对象的析构函数的时间。
例
#include <string>
struct Base;
struct Member {
Member(Base *b);
~Member();
Base *b_;
};
struct Base {
virtual void f() {}
virtual ~Base() {}
};
struct Derived : Base {
Derived() : m(this) {}
virtual ~Derived() {}
virtual void f() {}
std::string s;
Member m;
};
Member::Member(Base *b) : b_(b) {}
Member::~Member() {
// At this point, ~Derived has finished -- can we use b_ as a
// Derived* object (i.e. call Derived::f or access Derived::s)?
b_->f();
}
int main() {
Base *bd = new Derived;
delete bd;
}
在此示例中,Member
对象具有指向拥有它的Derived
对象的指针,并且它会尝试在Derived
对象被破坏时访问该对象...即使 Derived
的析构函数已经完成。
如果某个子对象在~Derived()
执行之后但在执行~Base()
之前调用虚函数,则会调用*bd
的虚函数的哪个版本? 当*bd
处于该状态时,访问它是否合法?
,从 [12.4] 开始,它清楚地表明它是不合法的:
尽管缺乏不再存在的定义为对象调用析构函数后,该对象将不再 存在;如果为析构函数调用 生存期已结束的对象 (3.8)。[示例: ...]
,但我认为,我可以说引用不再存在的对象会导致未定义的行为。
来自 n3290 [class.cdtor]
12.7 建造和破坏1 对于具有非平凡构造函数的对象,在构造函数开始执行之前引用对象的任何非静态成员或基类会导致未定义的行为。对于具有非平凡析构函数的对象,在析构函数完成执行后引用对象的任何非静态成员或基类会导致未定义的行为。
在你调用b_->f()
的那一刻,Derived
正在被破坏,但Base
还没有被破坏。不过,你仍然处于不确定状态,因为你要打电话的是Derived::f()
。
编辑:
成员函数,包括虚函数 (10.3),可以调用 在施工或销毁期间(12.6.2)。当虚拟函数 直接或间接从构造函数调用(包括从 数据成员的 mem 初始值设定项)或析构函数,以及 调用适用的对象是正在构造的对象或 破坏,调用的函数是构造函数中定义的函数 或析构函数自己的类或在其基之一中,但不是函数 在派生自构造函数或析构函数的类中重写它 类,或在最 派生对象 (1.8)。如果虚函数调用使用显式 类成员访问 (5.2.5) 和对象表达式引用 正在建造或破坏的对象,但其类型既不是 构造函数或析构函数自己的类或其基之一,结果 的调用未定义。
C++0x 工作草案 Sec 12.7 标准杆 4 杆
- Constexpr替代了新的放置方式,可以让内存中的对象保持未初始化状态
- 在容器上移动分配:以前包含的对象的状态
- MATLAB:跟踪imufilter对象中的状态变化
- 是否很好地使用状态模式来维护当前选定的对象?
- "Extern"对象问题:错误:Id 返回 1 个退出状态
- 访问处于"移自"状态的对象
- 是 *this = Ctor();清除对象状态的合法和高效?
- 设计模式中对象中的过程(方法和操作)的状态
- 如何保持异步函数中使用成员的shared_ptr对象的活动状态?
- 无法访问/存储地图中的游戏状态对象
- 单元测试 - 设置私人成员以获得所需的对象状态
- 在不同的运行中保持对象状态
- 调用 ~Derived() 和 ~Base() 之间的对象状态
- 异常安全 - 用于可靠回滚对象状态的模式
- 从函数中更改对象状态
- 正在更改const方法中的对象状态
- c++中对象状态的重构
- C++RAII来管理对象状态的更改和恢复
- 从默认构造函数调用重载构造函数时,维护对象状态信息
- c++11中的线程安全对象状态操作