【问题标题】:Does this C++ program invoke undefined behavior?这个 C++ 程序是否调用未定义的行为?
【发布时间】:2023-03-30 07:05:01
【问题描述】:

我正在阅读有关static_cast 运算符的信息。

考虑以下示例:

#include <iostream>
class B { };
class D : public B 
{
    public:
        void fun()
        {
            std::cout<<"fun() is called\n";
        }
};
void f(B* pb,D* pd)
{
    D* pd2=static_cast<D*>(pb);
    B* pb2=static_cast<B*>(pd);
    pd2->fun();
}
int main()
{
    B b;
    D d;
    f(&b,&d);
}

上面写着:

在下面的示例中,行 D* pd2 = static_cast(pb);是 不安全,因为 D 可以具有不在 B 中的字段和方法。 但是,行 B* pb2 = static_cast(pd);是一个安全的转换 因为 D 总是包含所有的 B。

与 dynamic_cast 相比,没有运行时检查 pb 的 static_cast 转换。 pb指向的对象可能不是 D 类型的对象,在这种情况下可以使用 *pd2 惨重。例如,调用一个属于 D 成员的函数 类,但不是 B 类,可能会导致访问冲突。

我在 gcc 4.8.1 和 MSVS 2010 上尝试过并获得输出 fun() 被调用。那么这个程序会调用未定义的行为吗?我的程序会在运行时崩溃吗? C++ 标准对此有何评论?如果我理解不正确,请纠正我。

【问题讨论】:

  • @Downvoters:谁投了反对票?为什么要投反对票?我的问题有什么问题?
  • @mah:语言明确说这是UB。不过,总的来说,您在这方面基本上是正确的。
  • 我没有投反对票,但那些投反对票的人可能已经这样做了,因为这个问题很愚蠢。为什么您期望在 X 类型的不相关对象上调用函数 Y::foo() 以具有明确定义的语义?这显然是荒谬的。
  • 它还能做什么?
  • @mah:我同意;我很惊喜。 :)

标签: c++ inheritance language-lawyer undefined-behavior static-cast


【解决方案1】:

是的,当然是。

通过强制从B*D* 的转换,您正在对仅是B 的对象调用D 的成员函数。

它“似乎可以工作”,因为所涉及的函数不会尝试访问任何实际数据,因此您的计算机在运行时没有内存访问需要注意和抱怨。


事实上,我们甚至不需要讨论函数调用是否有未定义的行为;演员阵容本身已经够糟糕了:

[C++14: 5.4.9/11]: 类型为“指向cv1 B”的纯右值,其中B是类类型,可以转换为“指向的指针”类型的纯右值em>cv2 D,”其中D 是从B 派生的类(第10 条),如果从“指向D”的有效标准转换为“指向B 的指针”存在 (4.10)cv2cv-qualification 相同或大于 cv-qualificationcv1 ,而B 既不是D 的虚拟基类,也不是D 的虚拟基类的基类。空指针值 (4.10) 被转换为目标类型的空指针值。 如果“指向 cv1 B 的指针”类型的纯右值指向实际上是 D 类型对象的子对象的 B,则生成的指针指向封闭的D 类型的对象。否则,行为未定义。

【讨论】:

  • 值得一提的是,函数f()中的强制转换本身不是未定义行为的实例(它可能被“指向cv1 B的指针”类型的prvalue所覆盖,它指向一个实际上是D' 子句类型对象的子对象,具体取决于传递给f() 的参数)。但是,f()main() 中的调用方式保证了未定义的行为。
  • @Arkadiy:是的,这完全取决于上下文。
【解决方案2】:

当您使用static_castB* 向上转换为D* 时,编译器相信您已经检查过这是正确的操作并且指针确实指向D。编译器或运行时无法代表您检查它(没有 RTTI)。因此,当您调用 foo 时,它会愉快地输入代码来调用它,并且因为它不是虚拟方法,所以会调用正确的 D::foo。如果您访问foo 中的任何D 特定成员,应用程序将崩溃、烧毁等。这就是现实。

理论上,您当然是在调用未定义的行为。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-19
    相关资源
    最近更新 更多