【问题标题】:Use static cast because dynamic cast fails. Bad practice?使用静态转换,因为动态转换失败。不好的做法?
【发布时间】:2017-08-09 10:06:24
【问题描述】:

在我正在进行的一个项目中,我注意到动态向下转换失败。快速的代码检查确认该特定对象实际上从未属于该类型。但是,我看到其他开发人员通过应用静态转换来强制执行相同的转换。

在我看来,这是一种危险的方法并且非常脆弱,如下例所示。这通常不是一种糟糕的编程习惯吗?

class Base
{
public:
    Base(){ m_p = 0; }
protected:
    int m_p;
};

class Derived: public Base
{
public:
    Derived(){ m_arr = new int[1]; }
    void Add_A() { m_p += 2; }
    void Add_B() { m_arr[0] += 3; }
private:
    int* m_arr;
};


Base* parent = new Base();

// obviously fails -> c_d is null
Derived* c_d = dynamic_cast<Derived*>(parent); 

Derived* c_s = static_cast<Derived*>(parent);
c_s->Add_A(); // works
c_s->Add_B(); // crashes, since m_arr does not exist.

【问题讨论】:

  • 它会调用 未定义的行为,所以是的 - 这是一种不好的做法
  • static_cast 具有未定义的行为。所以这种方法最终被打破了。
  • 您没有Derived 对象。再多的演员也不会改变这一点。

标签: c++ dynamic-cast static-cast


【解决方案1】:

使用static_cast 因为dynamic_cast 失败不仅是不好的做法,它几乎可以保证您的代码不正确和损坏。正如您在崩溃中所展示的那样,您永远不应该这样做,而是实际修复代码;使用其他演员表并不能解决您的任何问题。

但是, 有理由对static_cast 感到失望,即dynamic_cast 的运行时成本。如果您绝对确定dynamic_cast总是成功,则可以在性能限制要求的情况下将其替换为static_cast

(尽管在任何情况下你都应该重新考虑为什么你首先需要向下转换。另外,如果dynamic_cast 对于你的用例来说实际上太慢了,你很有可能不希望虚函数调用以.)

【讨论】:

    【解决方案2】:

    他们正在做的是调用未定义的行为。

    在这种情况下,未定义的行为正在做他们想做的事。在这个特定的来源中。在这个特定的编译器上。使用那些特定的编译器选项。

    这会让人很想继续做下去。毕竟,它有效。

    代价是每次更新编译器时,都应该检查它是否有效。每次修改编译器标志时,都应该检查它是否有效。每次使用它时,都应该检查它是否有效。互相计时。

    编译器的新版本(或新编译器,或现有编译器上的新标志)可以完全合法且合理地内联整个代码分支,请注意它确定性地包含未定义的行为,然后决定整个分支必须无法访问,并优化整个分支(有时包括测试)。

    这不是理论上的危险。它发生在 int 溢出中,其中 unsigned to int 未定义行为被证明并且分支被追溯消除。

    “它有效”是第 1 步。值得吗?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-05-14
      • 2017-09-22
      • 2011-02-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-14
      相关资源
      最近更新 更多