对象切片或UB风险

Object slicing or UB risk?

本文关键字:风险 UB 切片 对象      更新时间:2023-10-16

有几个基类在我的控制之外,像这样:-

class BaseNode // Just a POD class. No VTable
{
  void foo();
}
class BaseHost 
{
public:
  BaseNode *getNode()
  {
    ...
  } 
}

我想"扩展"BaseNode::foo的功能,但是类是有效密封的。

建议如下:-

class MyNode: public BaseNode 
{
  void foo()
  {
    // do my stuff..., then
    BaseNode::foo();
  }    
}
class MyHost: public BaseHost 
{
public:
  MyNode *getNode()
  {
    return (MyNode*) BaseHost::getNode(); // Slicing or UB risk?
  }   
}

如果MyNode引入额外的类成员或虚拟方法,事情将会变得严重错误-但如果满足这些约束,我仍然有UB吗?

还有其他问题吗?还是我需要重新考虑整个设计?

这种下拉法使用时要格外小心:它很容易导致UB。

标准保证您可以安全地从MyNode*转换为BaseNode*:

4.10/3:类型为"指向cv D的指针"的右值,其中D为类类型,可转换为类型为"指向cv B的指针"的右值,其中B是d的基类,如果B是不可访问的或有歧义的基类对于D,需要这种转换的程序是病态的。的的基类子对象的指针派生类对象。空指针值被转换为目的类型的空指针值。

但是让我们来玩火吧:标准还允许你在某些条件下从BaseNode*施放到MyNode*:

5.2.9/11:类型为"指向cv1 B的指针"的右值,其中B是类类型,可以转换为类型为"指向cv2 D的指针"的右值,其中D是从B派生的类,如果从的有效标准转换"指向D的指针"到"指向B的指针"存在,cv2也是一样cv-qualification等于或大于cv-qualification,且B是既不是D的虚基类,也不是D的虚基类的基类。空指针值被转换为空指针目的类型的值。如果"类型的右值指向"cv1 B"指向一个B,该B实际上是类型对象的子对象D,结果指针指向类型D的封闭对象。否则,行为是未定义的

我试着把这些引语翻译成纯文本:

  • 如果您确定BaseHost::getNode()返回指向MyNode对象的上行指针,并且在您的类层次结构中没有虚拟继承,那么就可以了。
  • 但是如果BaseHost::getNode()会返回其他东西(例如指向普通BaseNodeBaseNode的另一个兄弟派生的指针),您将拥有UB。
如前所述,这是危险的:在指针转换期间,甚至在您试图解引用指针之前,UB可能已经发生了。所以最好尽量避免。如果你有一个多态BaseNode类(例如,有一个虚拟析构函数),你可以使用一个更安全的dynamic_cast