是运行时糟糕的C风格铸件定义的行为

Is the behaviour for a runtime bad C-style cast defined?

本文关键字:定义 运行时 风格      更新时间:2023-10-16

如果您将旧的c风格从A型到类型B进行旧的C型铸件,则C 标准是否会定义特定的行为,而A型A类型A类型不能铸造为B型,反之亦然?

是否存在一种已知的可见行为,可以假定使用此操作时在运行时造成非法铸造的症状?

只有四个C - 样式铸件中的一个确定铸件在运行时的有效性,即dynamic_cast

c风格的铸件对应于其他三个铸件的组合(static_castreinterpret_castconst_cast)。这些铸件的有效性是在编译时确定的,或者如果无法在编译时间确定,则假定铸件是有效的。C风格的演员永远不会像dynamic_cast一样。

因此,在运行时"失败"的C风格铸件,即打破有效性假设,会导致不确定的行为。所以:

如果您将旧的C风格从A型到B型铸造,则C 标准是否会定义特定的行为,其中A型A类型不能铸造为B型,反之亦然?

no。

是否会有一种已知的可见行为可以假定是在运行时造成非法演员的症状?

no。

编译器会捕获其中的一些,但不是全部。这是灾难性演员的示例:

#include <iostream>
#include <string>
using namespace std;
class A {
public:
        A(std::string s, int x) : m_s(s), m_x(x) {} 
        void print() { cout << "A::print(): str = " << m_s << ", x = " << m_x << endl; }
private:  
        std::string m_s;
        int m_x;
};
class B {
public:
        B(int x) : m_x(x) {}
        void print() { m_x++; cout << "B::print(): x = " << m_x << endl; }
private:
        int m_x;
};
int main(int argc, char **argv) {
        A *a = new A("abc", 1);
        a->print();
        B *b = (B*)a;
        b->print();
        a->print();
        return 0;
}

在GCC上结果(Ubuntu 5.4.0-6ubuntu1〜16.04.4)5.4.0 20160609:

A::print(): str = abc, x = 1
B::print(): x = 24828977
A::print(): str = bc, x = 1

是的,我们在A数据的数据上称为B的方法,这意味着我们的C风格铸件作为reinterpret_castreinterpret_cast仅采用一个内存区域,允许您对待是不同的东西。这里没有安全带。

另一方面,如果您尝试编译类似的内容

    A a;
    B b;
    a = (A)b;
    return 0;

它将导致static_cast和编译时错误。因此,C风格的铸造结果取决于上下文。

处理模板和auto时,这是噩梦。

要避免此问题,请使用static_cast(用于编译时间检查)和dynamic_cast(用于运行时检查)或reinterpret_cast(用于指针和POD),清楚地说明了您的意图。