C++03 12.4/12对通过指针显式调用基类析构函数有何说明
What does C++03 12.4/12 say about calling a base class destructor explicitly through the pointer?
根据C++03 12.4/12,当显式调用析构函数时
如果对象不是析构函数的类类型,也不是从析构函数类类型派生的类,则程序具有未定义的行为
所以我有这个代码:
class Base {};
class Derived : public Base {};
char memory[100];
new(memory) Derived();
Base* ptr = (Base*)memory;
ptr->~Base();
这里的对象类型是Derived
,"析构函数的类类型"是Base
,因此根据标准措辞,看起来没有UB的依据。
那么,上面的代码是否根据标准生成UB?
正确,没有未定义的行为。
相比之下,根据涉及的类型,在这种情况下有潜在的UB:
Base *ptr = new Derived();
delete ptr;
原因是对于某些类型,实现可能已经应用了从Derived*
到Base*
的调整。因此,如果没有指向完整对象的指针,就无法正确释放内存分配。虚拟析构函数确保Base
子对象为实现提供足够的信息来恢复(虚拟调用机制必须能够恢复Derived*
指针,才能将其作为this
传递)。
但在你的例子中,内存并没有被释放,所以没有动机让它成为UB。当然,这仍然是一个坏主意,因为从概念上讲,Derived
对象处于损坏状态。您甚至没有合法的方式来调用~Derived
。在您的示例中,尽管这两种类型都是可破坏的,所以不需要来调用其中任何一种的析构函数。
它不是UB,因为这两个类都有平凡的析构函数,因此调用析构函数的效果与not调用析构因子的效果相同(no当然不是UB)。
如果我错了,请纠正我,我认为没有未定义的行为,但从人性(或可维护性)的角度来看,仍然应该避免。但是,考虑一下Derived
正在创建某种类型的成员,例如共享指针(即使在例外情况下,这也不是不典型的:)。我在我的机器上和代码板上都试过这个代码:
class Base {
public:
boost::shared_ptr<int> x;
};
class Derived : public Base {
public:
boost::shared_ptr<int> y;
};
int main(int argc, char *argv[]) {
boost::shared_ptr<int> xx(new int(0xff));
boost::shared_ptr<int> yy(new int(0xaa));
int memory[100];
for(int i=0; i<100; i++)
memory[i] = 0;
Derived* foo = new(memory) Derived();
foo->x = xx;
foo->y = yy;
(*foo->y)--;
Base* ptr = (Base*)foo;
ptr->~Base();
Derived* bar = new(memory) Derived();
bar->x = xx;
bar->y = yy;
foo->~Derived();
return 0;
}
这里是shared_ptryy没有发布,没有人可以保证永远不会忘记Derived不应该提供任何类型的东西。
相关文章:
- 使用基类指针创建对象时,缺少派生类析构函数
- 对具有动态分配的内存和析构函数的类对象的引用
- 基类中的默认析构函数禁用子类中的移动构造函数(如果有成员)
- 即使基类和派生类只使用基元数据类型,我是否需要定义虚拟析构函数
- C++11:我可以显式调用基类析构函数来销毁派生类吗
- 为什么我不能使用已删除或私有析构函数分配类的数组?
- 显式默认析构函数禁用类中的默认移动构造函数
- 具有受保护析构函数的类数组的动态分配
- 不带名称、构造函数或析构函数的类
- 我可以从析构函数的类方法调用它吗
- 否,除非函数返回具有抛出析构函数的类
- 析构函数子类中的 c++ 分段错误
- 从没有虚拟析构函数的类继承
- 非平凡的析构函数使类具有非平凡的可构造性
- 是否应该初始化具有未重写的纯虚拟析构函数的类
- 为什么带有用户定义析构函数的类的实例将成员指针设置为零
- 为什么不能对带有析构函数的类进行忆及
- 为什么不为定义了析构函数的类合成move操作呢?
- 在析构函数中将类成员设置为空
- 在第三方软件中派生没有虚析构函数的类