【问题标题】:When and why is an std::__non_rtti_object exception generated?何时以及为什么会生成 std​​::__non_rtti_object 异常?
【发布时间】:2009-05-12 21:02:11
【问题描述】:

我正在使用 Visual Studio 并执行有效的动态转换。 RTTI 已启用。

编辑:更新代码更真实

struct base
{
    virtual base* Clone()
    {
        base* ptr = new base;
        CopyValuesTo( ptr );
        return ptr;
    }
    virtual void CopyValuesTo( base* ptr )
    {
       ...
    }
    virtual ~base()
    {
    }
}

struct derived : public base
{
    virtual base* Clone()
    {
        derived* ptr = new derived;
        CopyValuesTo( ptr );
        return ptr;
    }
    virtual void CopyValuesTo( base* ptr )
    {
       ...
    }
    virtual ~derived()
    {
    }
}  

void Class1::UseNewSpec( base* in_ptr ) //part of a totally unrelated class
{
    derived* ptr = dynamic_cast<derived *>(in_ptr);
    if( !ptr )
       return;
    delete m_ptr;
    m_ptr = ptr->Clone(); //m_ptr is a member of Class1 of type base*
}

//usage : 
Class1 obj;
derived new_spec; 
obj.UseNewSpec( &new_spec );

我的调试器说在抛出异常时 in_ptr 是正确的类型。谷歌似乎特别没有帮助。有任何想法吗?干杯。

【问题讨论】:

  • 这是一个使用场景:UseNewSpec 链接到一个 GUI 旋钮。当旋钮改变时,调用 UseNewSpec。当旋钮缓慢移动时它可以工作,但是当它移动得非常快时会抛出这个异常。
  • 谢谢大家。我已经想通了。这是一个线程问题——其他地方的一些劣质代码导致指针在动态转换之前变得无效。

标签: c++ exception visual-studio-2005 rtti


【解决方案1】:

https://docs.microsoft.com/en-us/cpp/cpp/typeid-operator?view=vs-2019 有关于 __non_rtti_object_exception 的信息。

来自 MSDN:

如果指针不指向 有效对象,抛出 __non_rtti_objectexception,指示 尝试分析 RTTI 触发了故障(如访问 违反),因为对象是 不知何故无效(错误的指针或 代码不是用 /GR 编译的)。

【讨论】:

  • /GR 表示启用 RTTI。默认情况下已启用它。 /GR- 将其关闭。即使在命令行中显式添加 /GR 也无济于事。
【解决方案2】:

我根据您的伪代码运行了一个测试,它可以工作。因此,如果您的构建配置中真正启用了 RTTI,那么它一定是您发布的内容中未捕获的另一个问题。

【讨论】:

  • 万一以后有人碰到这篇文章,我遇到了类似的问题,结果我在代码中做了一些愚蠢的事情:我删除了 (valid, non-NULL) 上的一个对象指针从dynamic_cast 返回,然后继续在同一原始指针上调用dynamic_cast。这可能不是这个问题的问题,但我只是注意到这一点,以防其他人偶然发现这个问题,因为它很容易检查。
  • 对我来说这是一个非常相似的问题。不同之处在于,其他地方删除我正在使用的指针的伪劣代码甚至没有将指针设置为 NULL。因此,它看起来有效,但动态转换仍然失败。
  • 和你们有同样的问题,在悬空指针上调用dynamic_cast&lt;&gt;。谢谢
【解决方案3】:

动态转换周围的 RTTI 异常、失败或错误可能意味着您执行了非法转换。当且仅当 derived 类和 base 类都满足以下约束时,dynamic_cast&lt;derived*&gt;(ptrToBase) 才有效:该类或其基类之一具有虚拟成员函数。

这个虚成员函数可以是任何东西,包括析构函数。如果没有其他成员函数,可以试试:

struct base
{
    virtual ~base(){}
    ...
}

struct derived : public base
{
    ...
}

现在base 有一个虚成员函数,派生函数也是如此。试试看它是否能解决您的问题。

编辑-添加:

@carleeto -- 在“它已经有一个虚拟析构函数”中,它是否==base?

如果derived 具有虚拟析构函数但base 是非虚拟dtor,那么您仍然可能会收到此错误。

另外,您应该验证对象没有被破坏——一旦析构函数运行,调用 dynamic_cast 就不再安全了。尝试向 ctors 和 dtors 添加跟踪。

【讨论】:

  • 它已经有一个虚拟析构函数。我的错 - 我应该指出这一点。
【解决方案4】:

确保您在所有源文件中都启用了 RTTI。

否则指针无效。

【讨论】:

    【解决方案5】:

    base 是否包含任何 virtual 方法?它必须为了dynamic_cast 工作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-11-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多