确保dynamic_cast不会导致未定义的行为C ++

时间:2018-02-28 21:29:43

标签: c++ polymorphism undefined-behavior dynamic-cast

到目前为止,我认为如果我的课程AB之间没有任何关联,dynamic_cast使用指针将无法返回nullptr。现在我已经读到这会导致未定义的行为...

cppreference - dynamic_cast

  

当构造函数或析构函数中使用dynamic_cast(直接或间接),并且表达式引用当前正在构造/销毁的对象时,该对象被认为是派生最多的对象。如果new_type不是构造函数/析构函数自己的类或其基础之一的指针或引用,则行为未定义。

我有这样的代码:

class ActorComponent
{
    ActorComponent* m_parent;
public:
    template <typename _type>
    _type* getParent() const {
        return dynamic_cast<_type*>(m_parent);
    }

    ActorComponent(ActorComponent* parent) {
        // using `getParent` inside the constructor:
        auto p = this->getParent<int>(); // `int` obviously isn't base of the ActorComponent
    }
};

我需要将_type限制为

的类型
  • 等于ActorComponent
  • 派生自ActorComponent

......可能还有更多。

问题是:如何在编译时确保dynamic_cast这样的_type不会导致未定义的行为?简单

template <typename _type,
    typename = std::enable_if_t< std::is_base_of_v<ActorComponent, std::remove_cv_t<_type> > || std::is_same_v<ActorComponent, std::remove_cv_t<_type> > >

总是有效吗?

1 个答案:

答案 0 :(得分:3)

tl; dr 没关系。出于某种原因,您选择的条件显然不适用于您的代码。

你的引言:

  

如果new_type不是构造函数/析构函数自己的类或其基础的指针或引用,则行为未定义。

显然是在构造函数或析构函数中使用dynamic_cast,尽管由于某种原因你省略了完整的上下文:

  

使用dynamic_cast只能进行以下转换,...​​

     

1)...... 5)......

     

6)当构造函数或析构函数(直接或间接)使用dynamic_cast时,表达式引用当前正在构造/销毁的对象,该对象被认为是派生最多的对象。如果new_type不是指向构造函数/析构函数自己的类或其基础的指针或引用,则行为是未定义的。

由于你没有在构造函数或析构函数中使用它,因此案例6显然是无关紧要的。

与您的代码实际相关的案例是:

  

5)如果expression是多态类型Base的指针或引用,new_type是Derived类型的指针或引用,则执行运行时检查:

     
    

a)检查由表达式指向/识别的最派生对象。如果在该对象中,表达式指向/指向Derived的公共基础,并且如果只有一个派生类型的子对象是从由表达式指向/标识的子对象派生的,则转换结果/指向该派生子对象。 (这被称为“垂头丧气”。)

         

b)否则,如果表达式points /引用最派生对象的公共基础,并且同时,最派生的对象具有Derived类型的明确公共基类,则转换点的结果/指的是派生(这被称为“侧面”。)     c)否则,运行时检查失败。如果在指针上使用dynamic_cast,则返回new_type类型的空指针值。如果它在引用上使用,则抛出异常std :: bad_cast。

  

检查稍后编辑的代码:

ActorComponent(ActorComponent* parent) {
    // using `getParent` inside the constructor:
    // `int` obviously isn't base of the ActorComponent
    auto p = this->getParent<int>();
}

第6条第一部分的条件

  

在构造函数或析构函数中使用dynamic_cast(直接或间接)...

符合getParent代码间接在构造函数中),但第二部分:

  

...而表达式指的是当前正在构建/破坏的对象......

满意,因此第6条仍然不适用。

您正在投射m_parent,它是您正在构建的ActorComponent对象的成员子对象。由于成员子对象是在您进入构造函数体时完全构造的, 对象正在构造,我们不在该对象的构造函数。除了其他任何东西,该对象m_parent)是一个指针,它没有构造函数。顺便说一下,它是未初始化的,所以你的代码完全是非法的,但不是因为你问的原因。

相关问题