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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了确保dynamic_cast不会导致未定义的行为C ++相关的知识,希望对你有一定的参考价值。

直到今天,我认为如果我有类AB与任何方式无关,使用指针的dynamic_cast将无法返回nullptr。现在我已经读到这会导致未定义的行为......

cppreference - dynamic_cast

dynamic_cast用于构造函数或析构函数(直接或间接),而expression指的是当前正在构造/销毁的对象时,该对象被认为是派生最多的对象。如果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> > >

总能工作?

答案

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类型的明确公共基类,则转换点的结果/指的是Derived(This被称为“侧播”。)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)是一个指针,它没有构造函数。顺便说一句,它是未初始化的,所以你的代码完全是非法的,但不是因为你问的原因。

以上是关于确保dynamic_cast不会导致未定义的行为C ++的主要内容,如果未能解决你的问题,请参考以下文章

何时在空实例上调用成员函数会导致 C++11 中的未定义行为? [复制]

为啥 C-style cast 的行为与 dynamic_cast 不同?

以下链式赋值是不是会导致未定义的行为?

为啥受保护的继承会导致 dynamic_cast 失败?

C++ 类型索引散列导致未定义的行为

导致非标准行为的 #pragma 是不是会导致 __STDC__ 宏未定义为 1?