以下 reinterpret_cast 是否会导致未定义的行为?

Does the following reinterpret_cast lead to undefined behavior?

下面代码中的 reinterpret_cast 是否会导致未定义的行为?如果是这样,是否可以以类型安全的方式定义 rpd

class Base
{ 
public:
  virtual ~Base() = default;
};

class Derived : public Base { };

int main(void)
{
  Derived d;
  Base* pb = &d;
  Base*& rpb = pb;

  Derived*& rpd = reinterpret_cast<Derived*&>(rpb);

  return 0;
}

与我之前的 有点相关。这背后的背景;我正在试验一个适配器 class,它应该允许包含协变指针类型的向量本身用作协变类型。

演员表本身没有 UB(请参阅 [expr.reinterpret.cast]),但通过重新解释的引用 (rpd) 访问引用的指针 (rpb) 会:

[basic.lval](标准草案)

If a program attempts to access the stored value of an object through a glvalue of other than one of the following types the behavior is undefined:56

56) The intent of this list is to specify those circumstances in which an object may or may not be aliased.

  • (8.1) the dynamic type of the object,

不适用,动态类型是静态类型是Base*,不是Derived*是泛左值的类型。

  • (8.2) a cv-qualified version of the dynamic type of the object,

没有 cv 资格,类型仍然不匹配。

  • (8.3) a type similar to the dynamic type of the object,

不适用。这是关于 cv-qualifier de-compositions 的,见 [conv.qual](抱歉,段落中的许多下标很难输入 html 并且是保持文本可读性所必需的)。

  • (8.4) a type that is the signed or unsigned type corresponding to the dynamic type of the object,

仅与整数类型相关。

  • (8.5) a type that is the signed or unsigned type corresponding to a cv-qualified version of the dynamic type of the object,

同上。

  • (8.6) an aggregate or union type that includes one of the aforementioned types among its elements or non-static data members (including, recursively, an element or non-static data member of a subaggregate or contained union),

Derived* 既不是聚合也不是联合。

  • (8.7) a type that is a (possibly cv-qualified) base class type of the dynamic type of the object,

Derived* 不是 Base*.

的基数
  • (8.8) a char, unsigned char, or std​::​byte type.

Derived* 是其中的 none。


由于 none 的异常适用,通过 Derived* 类型的左值访问 Base* 的行为未定义。


I am experimenting with an adapter class that should allow vectors containing covariant pointer types to be used as covariant types themselves.

您的实验将无法坚持基本的面向对象原则。

基引用与派生对象是协变的,因为你不能通过基引用对派生对象做任何你不能对派生对象本身做的事情。

基类型的容器不能与派生的容器协变,因为你可以用基的容器(通过 "referencing" 的容器派生)做一些你不能用派生的容器做的事情: 添加其他派生类型的对象。

虽然,如果容器是不可变的...它可能在概念上可行。实际上用 C++ 实现它是另一回事。