9

我正在尝试了解static_castreinterpret_cast

如果我是正确的,标准(9.2.18)说reinterpret_cast对于 pod 数据是安全的:

一个指向 POD 结构对象的指针,使用 a 进行适当转换 reinterpret_cast,指向它的初始成员(或者如果该成员是位字段,则指向它所在的单元),反之亦然。[注意:因此,在 POD 结构对象中可能存在未命名的填充,但不是在其开头,这是实现适当对齐所必需的。——尾注]

我的问题是如何严格解释这一点。例如,布局兼容性是否足够?如果没有,为什么不呢?

对我来说,以下示例显示了一个示例,其中严格的“仅 POD 有效”解释似乎是错误的。

class complex_base  // a POD-class (I believe)
{
public:  
  double m_data[2];
};

class complex : public complex_base
{  //Not a POD-class (due to constructor and inheritance)
public:
  complex(const double real, const double imag); 
}

double* d = new double[4];
//I believe the following are valid because complex_base is POD
complex_base& cb1 = reinterpret_cast<complex_base&>(d[0]);  
complex_base& cb2 = reinterpret_cast<complex_base&>(d[2]);
//Does the following complete a valid cast to complex even though complex is NOT POD?
complex& c1 = static_cast<complex&>(cb1);
complex& c2 = static_cast<complex&>(cb2);

complex_base::m_data此外,如果受到保护(这意味着complex_base不是 pod),可能会破坏什么?[编辑:以及如何保护自己/检测此类破损]

在我看来,布局兼容性应该足够了——但这似乎不是标准所说的。

编辑:感谢您的回答。他们还帮我找到了这个, http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2342.htm

4

2 回答 2

5

我相信以下是有效的,因为 complex_base 是 POD

你错了。d[0]不引用complex_base对象的第一个成员。因此,它的对齐对于对象来说可能不够好complex_base,因此这样的演员表是不安全的(并且您引用的文本不允许这样做)。

即使 complex 不是 POD,以下是否完成了对 complex 的有效转换?

cb1并且cb2不要指向类型对象的子对象complex,因此static_cast会产生未定义的行为。参考C++03的5.2.9p5

If the lvalue of type "cv1 B" is actually a sub-object of an object of type D, the lvalue refers to the enclosing object of type D. Otherwise, the result of the cast is undefined.

It's not enough if merely the types involved fit together. The text talks about a pointer pointing to a POD-struct object and about an lvalue referring to a certain subobject. oth complex and complex_base are standard-layout objects. The C++0x spec says, instead of the text you quoted:

Is POD-ness requirement too strict?

This is a different question, not regarding your example code. Yes, requiring POD-ness is too strict. In C++0x this was recognized, and a new requirement which is more loose, "standard-layout" is given. I do think that both complex and complex_base are standard-layout classes, by the C++0x definition. The C++0x spec says, instead of the text you quoted:

A pointer to a standard-layout struct object, suitably converted using a reinterpret_cast, points to its initial member (or if that member is a bit-field, then to the unit in which it resides) and vice versa.

I interpret that as allowing to cast a pointer to a double, which actually points to a complex member (member by inheritance), to be casted to a complex*. A Standard-layout class is one that either has no base classes containing non-static data, or has only one base-class containing non-static data. Thus there is an unique "initial member".

于 2011-02-20T23:58:59.360 回答
1

可以打破的是非 POD 类实例可能具有 vtable 指针,以实现虚拟调度,如果它们具有任何虚拟函数,包括虚拟 dtor。vtbl 指针通常是非 POD 类的第一个成员。

(从技术上讲,虚拟调度不必以这种方式实现;实际上是这样。这就是为什么标准必须如此严格地规定什么是 POD 类型。)

老实说,我不确定为什么只有一个 ctor(“8.5.1(1):“聚合是一个数组或类(第 9 条),没有用户声明的构造函数(12.1)”)会使某些东西失去成为 POD 的资格。但是,确实如此。

当然,在您在这里的特殊情况下,不需要重新解释演员表。相反,只需向基类添加一个转换运算符:

class complex_base  // a POD-class (I believe)
{
public:  
  double m_data[2];
  operator double*() {
    return m_data;
  }
};


complex_base b; // create a complex_base
double* p = b; 

由于 complex_base 不是 double*,C++ 编译器将应用一个(并且只有一个)用户定义的转换运算符,以便将 b 分配给 p。这意味着p = b调用转换运算符,产生p = b.operator double*()(请注意,这实际上是合法的语法 - 您可以直接调用转换运算符,而不是您应该这样做),当然它会做任何事情,在这种情况下返回 m_data。

请注意,这是有问题的,因为我们现在可以直接访问 b 的内部。在实践中,我们可能会返回一个 const double*,或一个副本,或一个智能写时复制“指针”或 ...。

当然,在这种情况下,m_data 无论如何都是公开的,所以我们不会比我们写的更糟:

 double* p = b.m_data;

实际上,我们的情况要好一些,因为 complex_base 的客户不需要知道如何将其转换为双精度。

于 2011-02-20T23:58:49.660 回答